From 4ecc9796a773ca2103b24e218183905b9608415b Mon Sep 17 00:00:00 2001 From: Wesley Hershberger Date: Tue, 28 Apr 2026 13:00:18 -0500 Subject: [PATCH 01/26] doc: Project-aware member shutdown instructions Fixes #1361 Signed-off-by: Wesley Hershberger (cherry picked from commit 15e4e54a288792e893671fba5a54dd1d50089299) --- doc/how-to/member_shutdown.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/doc/how-to/member_shutdown.md b/doc/how-to/member_shutdown.md index da6d427d6..ab0de64aa 100644 --- a/doc/how-to/member_shutdown.md +++ b/doc/how-to/member_shutdown.md @@ -12,12 +12,16 @@ This guide provides instructions to safely shut down a MicroCloud cluster member (howto-member-shutdown-instances)= ## Stop or live-migrate all instances on the cluster member -To shut down a machine that is a MicroCloud cluster member, first ensure that it is not hosting any running LXD instances. +To shut down a machine that is a MicroCloud cluster member, first ensure that it is not hosting any running LXD instances. Check to make sure that no project has any running instances on the target cluster member: -You can stop all instances on a cluster member using the command: +```bash +lxc ls --all-projects +``` + +Explicitly shutting down LXD will shut down all instances running on that cluster member: ```bash -lxc stop --all +sudo snap stop lxd ``` Alternatively, for instances that can be {ref}`live-migrated `, you can migrate them to another cluster member without stopping them. See: {ref}`lxd:howto-instances-migrate` for more information. From 98510abf3f806a1371aff526867f7653695791ab Mon Sep 17 00:00:00 2001 From: Minae Lee Date: Tue, 5 May 2026 08:34:33 -0700 Subject: [PATCH 02/26] doc: update outdated links Signed-off-by: Minae Lee (cherry picked from commit 60209ec6b13cc6a06810b64d2b725b36459d8bec) Edited the note in `doc/how-to/install.md` to clarify that the snap channels shown are the LTS release and to provide a link to the feature release. Signed-off-by: Elijah Greenstein --- CONTRIBUTING.md | 6 +++--- doc/doc-cheat-sheet-myst.md | 2 +- doc/how-to/contribute.md | 6 +++--- doc/how-to/install.md | 5 +++++ doc/how-to/recover.md | 2 +- doc/how-to/support.md | 4 ++-- doc/index.md | 2 +- doc/reference/releases-snaps.md | 2 +- 8 files changed, 17 insertions(+), 12 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a0cc90078..88467b4b0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,17 +5,17 @@ The MicroCloud team welcomes contributions through pull requests, issue reports, and discussions. - Contribute to the code or documentation, report bugs, or request features in the [GitHub repository](https://github.com/canonical/microcloud). -- Ask questions or join discussions in the [MicroCloud forum](https://discourse.ubuntu.com/c/lxd/microcloud/145). +- Ask questions or join discussions in the [MicroCloud forum](https://discourse.ubuntu.com/c/project/lxd/microcloud/145). Review the following guidelines before contributing to the project. ## Code of Conduct -All contributors must adhere to the [Ubuntu Code of Conduct](https://ubuntu.com/community/ethos/code-of-conduct). +All contributors must adhere to the [Ubuntu Code of Conduct](https://ubuntu.com/community/docs/ethos/code-of-conduct). ## License and copyright -All external contributors must sign the [Canonical contributor license agreement (CCLA)](https://ubuntu.com/legal/contributors), which grants Canonical permission to use the contributions. +All external contributors must sign the [Canonical contributor license agreement (CCLA)](https://canonical.com/legal/contributors), which grants Canonical permission to use the contributions. - You retain copyright ownership of your contributions (no copyright assignment). - By default, contributions are licensed under the project's **AGPL-3.0-only** license. diff --git a/doc/doc-cheat-sheet-myst.md b/doc/doc-cheat-sheet-myst.md index 5662a7397..64a9c4204 100644 --- a/doc/doc-cheat-sheet-myst.md +++ b/doc/doc-cheat-sheet-myst.md @@ -19,7 +19,7 @@ myst: This file contains the syntax for commonly used Markdown and MyST markup. Open it in your text editor to quickly copy and paste the markup you need. -See the [MyST syntax guide](https://canonical-starter-pack.readthedocs-hosted.com/stable/reference/myst-syntax-reference/) for detailed information and conventions. +See the [MyST syntax guide](https://canonical-sphinx-stack.readthedocs-hosted.com/latest/reference/myst-syntax/) for detailed information and conventions. Also see the [MyST documentation](https://myst-parser.readthedocs.io/en/latest/index.html) for detailed information on MyST, and the [Canonical Documentation Style Guide](https://docs.ubuntu.com/styleguide/en) for general style conventions. diff --git a/doc/how-to/contribute.md b/doc/how-to/contribute.md index 13cc00b49..bc51a0432 100644 --- a/doc/how-to/contribute.md +++ b/doc/how-to/contribute.md @@ -30,7 +30,7 @@ Clarify concepts or common questions based on your own experience. Report documentation issues by opening an issue in [GitHub](https://github.com/canonical/microcloud/issues). : - We will evaluate and update the documentation as needed. -Ask questions or suggest improvements in the [MicroCloud forum](https://discourse.ubuntu.com/c/lxd/microcloud/145). +Ask questions or suggest improvements in the [MicroCloud forum](https://discourse.ubuntu.com/c/project/lxd/microcloud/145). : - We monitor discussions and update the documentation when necessary. If you contribute images to `doc/images`: @@ -39,9 +39,9 @@ If you contribute images to `doc/images`: ### Documentation framework -The MicroCloud documentation and its integrated documentation sets are built with [Sphinx](https://www.sphinx-doc.org/) and hosted on [Read the Docs](https://about.readthedocs.com/). For structuring, all use the [Diátaxis](https://diataxis.fr/) approach. +The MicroCloud documentation and its integrated documentation sets are built with [Sphinx](https://www.sphinx-doc.org/en/master/) and hosted on [Read the Docs](https://about.readthedocs.com/). For structuring, all use the [Diátaxis](https://diataxis.fr/) approach. -The MicroCloud and LXD documentation sets are written in [Markdown](https://commonmark.org/) with [MyST](https://myst-parser.readthedocs.io/) extensions. For syntax help and guidelines, see the [MyST style guide](https://canonical-documentation-with-sphinx-and-readthedocscom.readthedocs-hosted.com/style-guide-myst/) and the [documentation cheat sheet](cheat-sheet-myst) ([source](https://raw.githubusercontent.com/canonical/microcloud/main/doc/doc-cheat-sheet-myst.md)). +The MicroCloud and LXD documentation sets are written in [Markdown](https://commonmark.org/) with [MyST](https://myst-parser.readthedocs.io/en/latest/) extensions. For syntax help and guidelines, see the [MyST syntax guide](https://canonical-sphinx-stack.readthedocs-hosted.com/latest/reference/myst-syntax/) and the [documentation cheat sheet](cheat-sheet-myst) ([source](https://raw.githubusercontent.com/canonical/microcloud/main/doc/doc-cheat-sheet-myst.md)). The MicroCeph and MicroOVN documentation sets are written in a documentation markup language called [reStructuredText](https://docutils.sourceforge.io/rst.html) (`.rst`). Differences in functionality are few; however, syntax differs. diff --git a/doc/how-to/install.md b/doc/how-to/install.md index 6a3f2fa77..c0573b4d5 100644 --- a/doc/how-to/install.md +++ b/doc/how-to/install.md @@ -88,6 +88,11 @@ For detailed information, refer to {ref}`reference-requirements`. Install all required {ref}`snaps ` on each machine intended as a MicroCloud cluster member. Enter the following commands on all machines: +```{admonition} Snap channels +:class: note +The snap channels shown below install the current {ref}`LTS release ` of MicroCloud, along with the most recent compatible releases for its components. To install the {ref}`current feature release ` of MicroCloud instead, refer to the [install guide for that version](https://documentation.ubuntu.com/microcloud/latest/how-to/install/). +``` + ```bash sudo snap install lxd --channel=5.21/stable --cohort="+" sudo snap install microceph --channel=squid/stable --cohort="+" diff --git a/doc/how-to/recover.md b/doc/how-to/recover.md index b8ec1f1e1..ab40ad4c5 100644 --- a/doc/how-to/recover.md +++ b/doc/how-to/recover.md @@ -2,7 +2,7 @@ # How to recover a MicroCloud cluster ```{note} -Each MicroCloud service uses the [Dqlite](https://dqlite.io/) distributed +Each MicroCloud service uses the [Dqlite](https://canonical.com/dqlite) distributed database for highly-available storage. While the cluster recovery process is similar for each service, this document only covers cluster recovery for the `microcloudd` daemon. For cluster recovery procedures for LXD, MicroCeph and diff --git a/doc/how-to/support.md b/doc/how-to/support.md index e9423e2a5..d9c2d2ffd 100644 --- a/doc/how-to/support.md +++ b/doc/how-to/support.md @@ -9,7 +9,7 @@ You can seek support from the LXD developers as well as the wider community thro ### Forum -Ask questions or engage in discussions in our [Discourse forum](https://discourse.ubuntu.com/c/lxd/microcloud/145). +Ask questions or engage in discussions in our [Discourse forum](https://discourse.ubuntu.com/c/project/lxd/microcloud/145). ### Documentation @@ -27,5 +27,5 @@ You can find additional resources on the [MicroCloud website](https://canonical. LTS releases of MicroCloud receive standard support for five years, which means they receive continuous updates. Commercial support for MicroCloud is provided as part of [Ubuntu Pro](https://ubuntu.com/pro) (both Infra-only and full Ubuntu Pro). See the [full service description](https://ubuntu.com/legal/ubuntu-pro-description) for details. -Managed solutions and firefighting support are also available for MicroCloud deployments. Visit [Managed services](https://ubuntu.com/managed) for details. +Managed solutions and firefighting support are also available for MicroCloud deployments. Visit [Managed services](https://ubuntu.com/managed-infrastructure) for details. diff --git a/doc/index.md b/doc/index.md index 82190df4a..bd62054b2 100644 --- a/doc/index.md +++ b/doc/index.md @@ -58,7 +58,7 @@ MicroCloud is a member of the [Canonical](https://canonical.com) family. It’s ### Get involved - {ref}`Support ` -- [Discussion forum](https://discourse.ubuntu.com/c/lxd/microcloud/145) +- [Discussion forum](https://discourse.ubuntu.com/c/project/lxd/microcloud/145) - {ref}`Contribute ` ### Releases diff --git a/doc/reference/releases-snaps.md b/doc/reference/releases-snaps.md index 7816f925f..72406b500 100644 --- a/doc/reference/releases-snaps.md +++ b/doc/reference/releases-snaps.md @@ -24,7 +24,7 @@ Refer to {ref}`howto-update-upgrade` and {ref}`howto-snap` for additional detail (ref-releases-microcloud)= ## MicroCloud releases -The MicroCloud team maintains both Long Term Support (LTS) and feature releases in parallel. Release notes are published on [Discourse](https://discourse.ubuntu.com/c/lxd/microcloud/145/). +The MicroCloud team maintains both Long Term Support (LTS) and feature releases in parallel. Release notes are published on [Discourse](https://discourse.ubuntu.com/c/project/lxd/microcloud/145). (ref-releases-microcloud-lts)= ### LTS releases From 37e62f6e7d37d4f150304588f9f96c365a1bb635 Mon Sep 17 00:00:00 2001 From: Minae Lee Date: Tue, 28 Apr 2026 23:17:14 -0700 Subject: [PATCH 03/26] doc: add markdown linter Signed-off-by: Minae Lee (cherry picked from commit fb72f4f22c88f5b03e251383deb4724028616e34) --- .github/workflows/markdown-style-checks.yml | 40 +++++++++++++++++++++ doc/.sphinx/.pymarkdown.json | 39 ++++++++++++++++++++ doc/Makefile | 36 +++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 .github/workflows/markdown-style-checks.yml create mode 100644 doc/.sphinx/.pymarkdown.json diff --git a/.github/workflows/markdown-style-checks.yml b/.github/workflows/markdown-style-checks.yml new file mode 100644 index 000000000..1887687db --- /dev/null +++ b/.github/workflows/markdown-style-checks.yml @@ -0,0 +1,40 @@ +name: Markdown style checks + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + # Make sure bash is always invoked with `-eo pipefail` + # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsshell + shell: bash + +on: + workflow_call: + push: + branches: + - main + paths: + - 'doc/**' # Only run on changes to the doc directory + pull_request: + paths: + - 'doc/**' # Only run on changes to the doc directory + +jobs: + markdown-lint: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + persist-credentials: false + - name: Create venv + working-directory: "doc" + run: make install + - name: Lint markdown + working-directory: "doc" + run: make lint-md diff --git a/doc/.sphinx/.pymarkdown.json b/doc/.sphinx/.pymarkdown.json new file mode 100644 index 000000000..a93ca3e6b --- /dev/null +++ b/doc/.sphinx/.pymarkdown.json @@ -0,0 +1,39 @@ +{ + "plugins": { + "selectively_enable_rules": true, + "heading-style": { + "enabled": true, + "style": "atx" + }, + "commands-show-output": { + "enabled": true + }, + "no-missing-space-atx": { + "enabled": true + }, + "heading-start-left": { + "enabled": true + }, + "no-trailing-punctuation": { + "enabled": true, + "punctuation": ".,;。،;" + }, + "blanks-around-lists": { + "enabled": true + }, + "hr-style": { + "enabled": true + }, + "no-empty-links": { + "enabled": true + }, + "no-alt-text": { + "enabled": true + } + }, + "extensions": { + "front-matter" : { + "enabled" : true + } + } +} \ No newline at end of file diff --git a/doc/Makefile b/doc/Makefile index 2818b750d..416a9ad35 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -15,6 +15,12 @@ LXDVERSION = origin/stable-5.21 MICROCEPHVERSION = 64d02d9538a89be039707ecbf942ca1aeae29760 # origin/main. MICROOVNVERSION = origin/branch-24.03 +SPHINX_DIR ?= .sphinx +DOCS_SOURCEDIR ?= . +DOCS_VENVDIR ?= $(SPHINX_DIR)/venv +DOCS_VENV ?= $(DOCS_VENVDIR)/bin/activate +INTEGRATION_DIR ?= integration + # Put it first so that "make" without argument is like "make help". help: @echo "\n" \ @@ -31,6 +37,7 @@ help: "* check accessibility: make pa11y \n" \ "* check style guide compliance: make vale \n" \ "* check style guide compliance on target: make vale TARGET=* \n" \ + "* check markdown: make lint-md \n" \ "* other possible targets: make \n" \ "------------------------------------------------------------- \n" @@ -112,6 +119,35 @@ serve: html serve-microcloud: microcloud cd $(current_dir)/_build/; python3 -m http.server --bind 127.0.0.1 8000 +pymarkdownlnt-install: install + @. $(DOCS_VENV); test -d $(DOCS_VENVDIR)/lib/python*/site-packages/pymarkdown || pip install pymarkdownlnt==0.9.35 + +# Without --return-code-scheme explicit, pymarkdownlnt returns 1 for multiple scenarios +# By using the explicit scheme, it only returns 1 when no files are found, +# which should not result in failure +lint lint-md: pymarkdownlnt-install + @echo "Running Markdown linting..." + @. $(DOCS_VENV); pymarkdownlnt \ + --config $(SPHINX_DIR)/.pymarkdown.json \ + --return-code-scheme explicit \ + scan \ + --recurse \ + --exclude=$(SPHINX_DIR)/** \ + --exclude=$(DOCS_VENVDIR)/** \ + --exclude=$(INTEGRATION_DIR)/** \ + $(DOCS_SOURCEDIR); \ + status=$$?; \ + if [ $$status -eq 1 ]; then \ + echo "No Markdown files selected for linting"; \ + echo "Passed"; \ + exit 0; \ + elif [ $$status -ne 0 ]; then \ + echo "Failed"; \ + exit $$status; \ + else \ + echo "Passed"; \ + fi; + install: $(MAKE) -f Makefile.sp sp-install ADDPREREQS='pyyaml' From f9145dd424179ce0877157db07490df1163cd322 Mon Sep 17 00:00:00 2001 From: Minae Lee Date: Tue, 28 Apr 2026 23:19:18 -0700 Subject: [PATCH 04/26] doc: fix lint issues in markdown files Signed-off-by: Minae Lee (cherry picked from commit a0f1726a07eb6eeff099c3617f4330fc250158a8) --- doc/how-to/snaps.md | 1 + doc/tutorial/multi-member.md | 1 + 2 files changed, 2 insertions(+) diff --git a/doc/how-to/snaps.md b/doc/how-to/snaps.md index bb50cc55f..eba06fd1f 100644 --- a/doc/how-to/snaps.md +++ b/doc/how-to/snaps.md @@ -67,6 +67,7 @@ For more information about managing snap services, visit {ref}`snap:how-to-guide ## Related topics How-to guides: + - {ref}`howto-update-upgrade` - {ref}`howto-install` diff --git a/doc/tutorial/multi-member.md b/doc/tutorial/multi-member.md index 01f13657b..374d471f9 100644 --- a/doc/tutorial/multi-member.md +++ b/doc/tutorial/multi-member.md @@ -703,6 +703,7 @@ We continue using `micro1`, but you will see the same results on the others. 1. Within the output of the previous command (`lxc network show default`), find the value for `volatile.network.ipv4.address`. This is the virtual router's IPv4 address. 1. Ping that IPv4 address. + ```{terminal} :input: ping 192.0.2.100 :user: root From 4751a24914ad1639a018a4a5c18685dfa8380dd7 Mon Sep 17 00:00:00 2001 From: Minae Lee Date: Thu, 7 May 2026 10:37:41 -0700 Subject: [PATCH 05/26] doc: add documentation organization info to homepage Add the "How this documentation is organized" section, a required part of standard Canonical docs home pages. Signed-off-by: Minae Lee (cherry picked from commit 48d69e3b95ad31b85ee4494b5e5eca6548d91875) --- doc/index.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/doc/index.md b/doc/index.md index bd62054b2..90cd6a0d2 100644 --- a/doc/index.md +++ b/doc/index.md @@ -2,8 +2,8 @@ myst: html_meta: description: MicroCloud is a lightweight, open source cloud platform built on LXD, MicroCeph, and MicroOVN, ideal for private cloud, edge computing, and test labs. -discourse: lxc:[Introducing MicroCloud](15871) relatedlinks: "[Install MicroCloud on Linux | Snap Store](https://snapcraft.io/microcloud)" +discourse: lxc:[Introducing MicroCloud](15871) --- (home)= @@ -51,6 +51,17 @@ Also, while each component's documentation includes instructions for removing cl --- +## How this documentation is organized + +This documentation uses the [Diátaxis documentation structure](https://diataxis.fr/). + +- The {ref}`tutorials` introduce you to MicroCloud concepts and usage. +- The {ref}`howto` provide detailed setup and usage instructions, including how to access the UI and manage cluster members. +- The {ref}`reference` guides provide technical details, release notes, and common CLI commands. +- The {ref}`explanation` section includes topic overviews and detailed explanations of key concepts, such as local versus distributed storage. + +--- + ## Project and community MicroCloud is a member of the [Canonical](https://canonical.com) family. It’s an open source project that warmly welcomes community contributions, suggestions, fixes, and constructive feedback. @@ -73,15 +84,12 @@ MicroCloud is a member of the [Canonical](https://canonical.com) family. It’s Thinking about using MicroCloud for your next project? [Get in touch](https://canonical.com/microcloud/contact-us)! - - - ```{toctree} :hidden: :maxdepth: 2 self -Tutorials +/tutorial/index /how-to/index /reference/index /explanation/index From 9fe8ab88888432ebfefae213c93449b06a53ba0d Mon Sep 17 00:00:00 2001 From: Minae Lee Date: Thu, 7 May 2026 10:54:23 -0700 Subject: [PATCH 06/26] doc: only link to product page in homepage related links Signed-off-by: Minae Lee (cherry picked from commit 7aab87c2a3e1161849ce73299d9f31c880cf714a) --- doc/index.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/index.md b/doc/index.md index 90cd6a0d2..49df0c7bc 100644 --- a/doc/index.md +++ b/doc/index.md @@ -2,8 +2,7 @@ myst: html_meta: description: MicroCloud is a lightweight, open source cloud platform built on LXD, MicroCeph, and MicroOVN, ideal for private cloud, edge computing, and test labs. -relatedlinks: "[Install MicroCloud on Linux | Snap Store](https://snapcraft.io/microcloud)" -discourse: lxc:[Introducing MicroCloud](15871) +relatedlinks: "[MicroCloud: your open source cloud platform](https://canonical.com/microcloud)" --- (home)= From 96034558a75a481e4b299743fe2f46b961b6f198 Mon Sep 17 00:00:00 2001 From: Elijah Greenstein Date: Thu, 14 May 2026 18:36:43 +0200 Subject: [PATCH 07/26] doc/custom_conf.py: Update MicroCeph URL The MicroCeph URL has changed from Read the Docs to `documentation.ubuntu.com`. This commit updates `custom_conf.py` so that the MicroCeph `objects.inv` file can be accessed from the new URL. Signed-off-by: Elijah Greenstein (cherry picked from commit dd6afce570307fd8fa7a38627002ea15006b1052) Edited the MicroCeph URL to point to the documentation for `v19.2.0-squid`. Edited the MicroOVN URL to use the MicroOVN documentation site (similar to the LXD and MicroCeph URLs) and point to version `24.03`. --- doc/custom_conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/custom_conf.py b/doc/custom_conf.py index 7a4518901..02f54226c 100644 --- a/doc/custom_conf.py +++ b/doc/custom_conf.py @@ -277,8 +277,8 @@ if ('SINGLE_BUILD' in os.environ and os.environ['SINGLE_BUILD'] == 'True'): intersphinx_mapping = { 'lxd': ('https://documentation.ubuntu.com/lxd/stable-5.21/', None), - 'microceph': ('https://canonical-microceph.readthedocs-hosted.com/en/v19.2.0-squid/', None), - 'microovn': ('https://documentation.ubuntu.com/microcloud/v2/microovn/', None), + 'microceph': ('https://documentation.ubuntu.com/canonical-microceph/v19.2.0-squid/', None), + 'microovn': ('https://canonical-microovn.readthedocs-hosted.com/en/24.03/', None), } elif ('READTHEDOCS' in os.environ) and (os.environ['READTHEDOCS'] == 'True'): intersphinx_mapping = { From a23090029bbf44a8f7dc1e054e1a96908f387647 Mon Sep 17 00:00:00 2001 From: Minae Lee Date: Thu, 30 Apr 2026 17:10:36 -0700 Subject: [PATCH 08/26] doc: remove use of build_requirements.py Signed-off-by: Minae Lee Signed-off-by: Elijah Greenstein Amended to update gitpython to 3.1.50. (cherry picked from commit 68bdba7f34f5b73890ecadbde281f2ad51781742) --- .github/workflows/tests.yml | 1 + doc/.gitignore | 1 - doc/.readthedocs.yaml | 2 +- doc/.sphinx/build_requirements.py | 127 ------------------------------ doc/Makefile.sp | 18 +---- doc/conf.py | 32 +++----- doc/requirements.txt | 37 +++++++++ 7 files changed, 52 insertions(+), 166 deletions(-) delete mode 100644 doc/.sphinx/build_requirements.py create mode 100644 doc/requirements.txt diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0c2221b80..3592f3aa3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -297,6 +297,7 @@ jobs: with: working-directory: './doc' makefile: 'Makefile' + python-version: '3.12' snap: name: Trigger snap edge build diff --git a/doc/.gitignore b/doc/.gitignore index cdc1f1f3d..1d39bb85b 100644 --- a/doc/.gitignore +++ b/doc/.gitignore @@ -1,6 +1,5 @@ /*env*/ .sphinx/venv/ -.sphinx/requirements.txt .sphinx/warnings.txt .sphinx/.wordlist.dic .sphinx/.doctrees/ diff --git a/doc/.readthedocs.yaml b/doc/.readthedocs.yaml index 3df760f20..1796093af 100644 --- a/doc/.readthedocs.yaml +++ b/doc/.readthedocs.yaml @@ -35,4 +35,4 @@ sphinx: # Optionally declare the Python requirements required to build your docs python: install: - - requirements: doc/.sphinx/requirements.txt + - requirements: doc/requirements.txt diff --git a/doc/.sphinx/build_requirements.py b/doc/.sphinx/build_requirements.py deleted file mode 100644 index c9511800c..000000000 --- a/doc/.sphinx/build_requirements.py +++ /dev/null @@ -1,127 +0,0 @@ -import sys - -sys.path.append('./') -from custom_conf import * - -# The file contains helper functions and the mechanism to build the -# .sphinx/requirements.txt file that is needed to set up the virtual -# environment. - -# You should not do any modifications to this file. Put your custom -# requirements into the custom_required_modules array in the custom_conf.py -# file. If you need to change this file, contribute the changes upstream. - -legacyCanonicalSphinxExtensionNames = [ - "youtube-links", - "related-links", - "custom-rst-roles", - "terminal-output" - ] - -def IsAnyCanonicalSphinxExtensionUsed(): - for extension in custom_extensions: - if (extension.startswith("canonical.") or - extension in legacyCanonicalSphinxExtensionNames): - return True - - return False - -def IsNotFoundExtensionUsed(): - return "notfound.extension" in custom_extensions - -def IsSphinxTabsUsed(): - for extension in custom_extensions: - if extension.startswith("sphinx_tabs."): - return True - - return False - -def AreRedirectsDefined(): - return ("sphinx_reredirects" in custom_extensions) or ( - ("redirects" in globals()) and \ - (redirects is not None) and \ - (len(redirects) > 0)) - -def IsOpenGraphConfigured(): - if "sphinxext.opengraph" in custom_extensions: - return True - - for global_variable_name in list(globals()): - if global_variable_name.startswith("ogp_"): - return True - - return False - -def IsMyStParserUsed(): - return ("myst_parser" in custom_extensions) or \ - ("custom_myst_extensions" in globals()) - -def DeduplicateExtensions(extensionNames: [str]): - extensionNames = dict.fromkeys(extensionNames) - resultList = [] - encounteredCanonicalExtensions = [] - - for extensionName in extensionNames: - if extensionName in legacyCanonicalSphinxExtensionNames: - extensionName = "canonical." + extensionName - - if extensionName.startswith("canonical."): - if extensionName not in encounteredCanonicalExtensions: - encounteredCanonicalExtensions.append(extensionName) - resultList.append(extensionName) - else: - resultList.append(extensionName) - - return resultList - -if __name__ == "__main__": - requirements = [ - "furo", - "pyspelling", - "sphinx", - "sphinx-autobuild", - "sphinx-copybutton", - "sphinx-design", - "sphinxcontrib-jquery", - "watchfiles", - "GitPython" - - ] - - requirements.extend(custom_required_modules) - - if IsAnyCanonicalSphinxExtensionUsed(): - requirements.append("canonical-sphinx-extensions==0.0.27") - - if IsNotFoundExtensionUsed(): - requirements.append("sphinx-notfound-page") - - if IsSphinxTabsUsed(): - requirements.append("sphinx-tabs") - - if AreRedirectsDefined(): - requirements.append("sphinx-reredirects") - - if IsOpenGraphConfigured(): - requirements.append("sphinxext-opengraph") - - if IsMyStParserUsed(): - requirements.append("myst-parser==4.0.1") - requirements.append("linkify-it-py") - - # removes duplicate entries - requirements = list(dict.fromkeys(requirements)) - requirements.sort() - - with open(".sphinx/requirements.txt", 'w') as requirements_file: - requirements_file.write( - "# DO NOT MODIFY THIS FILE DIRECTLY!\n" - "#\n" - "# This file is generated automatically.\n" - "# Add custom requirements to the custom_required_modules\n" - "# array in the custom_conf.py file and run:\n" - "# make clean && make install\n") - - for requirement in requirements: - requirements_file.write(requirement) - requirements_file.write('\n') diff --git a/doc/Makefile.sp b/doc/Makefile.sp index 61c42cf82..e258a8b66 100644 --- a/doc/Makefile.sp +++ b/doc/Makefile.sp @@ -27,23 +27,12 @@ sp-full-help: $(VENVDIR) @echo "\n\033[1;31mNOTE: This help texts shows unsupported targets!\033[0m" @echo "Run 'make help' to see supported targets." -# Shouldn't assume that venv is available on Ubuntu by default; discussion here: -# https://bugs.launchpad.net/ubuntu/+source/python3.4/+bug/1290847 -$(SPHINXDIR)/requirements.txt: - @python3 -c "import venv" || \ - (echo "You must install python3-venv before you can build the documentation."; exit 1) - python3 -m venv $(VENVDIR) - @if [ ! -z "$(ADDPREREQS)" ]; then \ - . $(VENV); pip install --require-virtualenv $(ADDPREREQS); \ - fi - . $(VENV); python3 $(SPHINXDIR)/build_requirements.py - # If requirements are updated, venv should be rebuilt and timestamped. -$(VENVDIR): $(SPHINXDIR)/requirements.txt +$(VENVDIR): @echo "... setting up virtualenv" - python3 -m venv $(VENVDIR) + python3 -m venv $(VENVDIR) || { echo "You must install python3-venv before you can build the documentation."; exit 1; } . $(VENV); pip install --require-virtualenv \ - --upgrade -r $(SPHINXDIR)/requirements.txt \ + --upgrade -r requirements.txt \ --log $(VENVDIR)/pip_install.log @test ! -f $(VENVDIR)/pip_list.txt || \ mv $(VENVDIR)/pip_list.txt $(VENVDIR)/pip_list.txt.bak @@ -79,7 +68,6 @@ sp-serve: sp-html sp-clean: sp-clean-doc @test ! -e "$(VENVDIR)" -o -d "$(VENVDIR)" -a "$(abspath $(VENVDIR))" != "$(VENVDIR)" rm -rf $(VENVDIR) - rm -f $(SPHINXDIR)/requirements.txt rm -rf $(SPHINXDIR)/node_modules/ rm -rf $(SPHINXDIR)/styles rm -rf $(SPHINXDIR)/vale.ini diff --git a/doc/conf.py b/doc/conf.py index 6d0d0d76d..5debf0a78 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -8,7 +8,6 @@ sys.path.append('./') from custom_conf import * sys.path.append('.sphinx/') -from build_requirements import * # Configuration file for the Sphinx documentation builder. # You should not do any modifications to this file. Put your custom @@ -22,34 +21,23 @@ ### Extensions ############################################################ +# Custom MyST syntax extensions; see +# https://myst-parser.readthedocs.io/en/latest/syntax/optional.html +# +# NOTE: By default, the following MyST extensions are enabled: +# substitution, deflist, linkify +myst_enable_extensions = set() + extensions = [ 'sphinx_design', 'sphinx_copybutton', 'sphinxcontrib.jquery', + 'sphinx_reredirects', + 'myst_parser', + 'sphinxext.opengraph', ] -# Only add redirects extension if any redirects are specified. -if AreRedirectsDefined(): - extensions.append('sphinx_reredirects') - -# Only add myst extensions if any configuration is present. -if IsMyStParserUsed(): - extensions.append('myst_parser') - - # Additional MyST syntax - myst_enable_extensions = [ - 'substitution', - 'deflist', - 'linkify' - ] - myst_enable_extensions.extend(custom_myst_extensions) - -# Only add Open Graph extension if any configuration is present. -if IsOpenGraphConfigured(): - extensions.append('sphinxext.opengraph') - extensions.extend(custom_extensions) -extensions = DeduplicateExtensions(extensions) ### Configuration for extensions diff --git a/doc/requirements.txt b/doc/requirements.txt new file mode 100644 index 000000000..c82507181 --- /dev/null +++ b/doc/requirements.txt @@ -0,0 +1,37 @@ +furo +canonical-sphinx-extensions + +# Extensions previously auto-loaded by canonical-sphinx +myst-parser~=4.0 # v5.0.0 causes version conflicts +sphinx-autobuild==2025.8.25 +sphinx-design==0.6.1 +sphinx-notfound-page~=1.1 +sphinx-reredirects==0.1.6 +sphinx-tabs~=3.5 +sphinxcontrib-jquery~=4.1 +sphinxext-opengraph~=0.13 + +# Extra extensions, previously bundled as canonical-sphinx-extensions +sphinx-config-options~=0.1 +sphinx-filtered-toctree~=0.1 +sphinx-related-links~=0.1 +sphinx-roles~=0.1 +sphinx-terminal~=1.0 +sphinx-youtube-links~=0.1 + +# Other dependencies +packaging~=26.1 +pyspelling +sphinxcontrib-svg2pdfconverter[CairoSVG]~=2.1 +sphinx-last-updated-by-git~=0.3 +sphinx-sitemap~=2.9 + +# Vale dependencies +vale~=3.13 + +# MicroCloud custom dependencies +gitpython==3.1.50 +linkify-it-py==2.0.3 +pyyaml==6.0.3 +sphinx-copybutton==0.5.2 +watchfiles==1.1.1 From 9c0565952a83b235a25b8236165f26199b01126b Mon Sep 17 00:00:00 2001 From: Minae Lee Date: Fri, 1 May 2026 14:35:03 -0700 Subject: [PATCH 09/26] doc: merge conf.py and custom_conf.py Moves code from custom_conf.py into conf.py and aligns it with the Sphinx Stack (formerly the Sphinx Starter Pack). This deliberately excludes the code for the Swagger UI, which will be added into conf.py in a separate commit to make this change easier to backport to the v2-edge branch, which does not use Swagger UI. Signed-off-by: Minae Lee Signed-off-by: Elijah Greenstein Amended to include update to MicroCeph URL following migration from Read the Docs to documentation.ubuntu.com. (cherry picked from commit 407db1816c95e2de9324e77b0743a8e3b2f25363) Edited `intersphinx_mapping` for `SINGLE_BUILD` to use URLs for pinned versions of LXD (`stable-5.21`), MicroCeph (`v19.2.0-squid`), and MicroOVN (`24.03`) documentation. Removed `html_extra_path`, as it is used for the Cluster Manager API (specific to MicroCloud 3). --- doc/conf.py | 392 ++++++++++++++++++++++++++++----------------- doc/custom_conf.py | 331 -------------------------------------- 2 files changed, 247 insertions(+), 476 deletions(-) delete mode 100644 doc/custom_conf.py diff --git a/doc/conf.py b/doc/conf.py index 5debf0a78..9fd6df386 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -1,122 +1,228 @@ -import sys +import datetime import os -import requests -from urllib.parse import urlparse -from git import Repo, InvalidGitRepositoryError -import time +import yaml + +############################ +# MicroCloud custom configuration # +############################ + +import sys +from git import Repo +import re sys.path.append('./') -from custom_conf import * sys.path.append('.sphinx/') -# Configuration file for the Sphinx documentation builder. -# You should not do any modifications to this file. Put your custom -# configuration into the custom_conf.py file. -# If you need to change this file, contribute the changes upstream. -# -# For the full list of built-in configuration values, see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html +from redirects import redirects -############################################################ -### Extensions -############################################################ +with open('../version/version.go') as f: + match = re.search(r'RawVersion = "([^"]+)"', f.read()) + version = match.group(1) if match else '' -# Custom MyST syntax extensions; see -# https://myst-parser.readthedocs.io/en/latest/syntax/optional.html -# -# NOTE: By default, the following MyST extensions are enabled: -# substitution, deflist, linkify -myst_enable_extensions = set() -extensions = [ - 'sphinx_design', - 'sphinx_copybutton', - 'sphinxcontrib.jquery', - 'sphinx_reredirects', - 'myst_parser', - 'sphinxext.opengraph', -] +####################### +# Project information # +####################### -extensions.extend(custom_extensions) +project = 'MicroCloud' +author = "Canonical Ltd." -### Configuration for extensions +# Sidebar documentation title; best kept reasonably short +# To disable the title, set to an empty string. +html_title = project + ' documentation ' + version -# Used for related links -if not 'discourse_prefix' in html_context and 'discourse' in html_context: - html_context['discourse_prefix'] = html_context['discourse'] + '/t/' +# Copyright string; shown at the bottom of the page +copyright = '2014-%s AGPL-3.0, %s' % (datetime.date.today().year, author) -# The URL prefix for the notfound extension depends on whether the documentation uses versions. -# For documentation on documentation.ubuntu.com, we also must add the slug. -url_version = '' -url_lang = '' +# Use RTD canonical URL to ensure duplicate pages have a single canonical URL +# that includes the version (such as /latest/); helps SEO. +html_baseurl = os.environ.get('READTHEDOCS_CANONICAL_URL', '/') -# Determine if the URL uses versions and language -if 'READTHEDOCS_CANONICAL_URL' in os.environ and os.environ['READTHEDOCS_CANONICAL_URL']: - url_parts = os.environ['READTHEDOCS_CANONICAL_URL'].split('/') +# OpenGraph metadata used for social sharing previews +ogp_site_url = html_baseurl +ogp_site_name = html_title +ogp_image = 'https://documentation.ubuntu.com/microcloud/latest/_static/tag.png' - if len(url_parts) >= 2 and 'READTHEDOCS_VERSION' in os.environ and os.environ['READTHEDOCS_VERSION'] == url_parts[-2]: - url_version = url_parts[-2] + '/' +html_favicon = '.sphinx/_static/favicon.png' - if len(url_parts) >= 3 and 'READTHEDOCS_LANGUAGE' in os.environ and os.environ['READTHEDOCS_LANGUAGE'] == url_parts[-3]: - url_lang = url_parts[-3] + '/' +html_context = { + 'product_page': 'canonical.com/microcloud', + 'product_tag': '_static/tag.png', -# Set notfound_urls_prefix to the slug (if defined) and the version/language affix -if slug: - notfound_urls_prefix = '/' + slug + '/' + url_lang + url_version -elif len(url_lang + url_version) > 0: - notfound_urls_prefix = '/' + url_lang + url_version -else: - notfound_urls_prefix = '' + 'discourse': 'https://discourse.ubuntu.com/c/lxd/microcloud/', + 'discourse_prefix': { + 'ubuntu': 'https://discourse.ubuntu.com/t/', + 'lxc': 'https://discuss.linuxcontainers.org/t/', + }, -notfound_context = { - 'title': 'Page not found', - 'body': '

Sorry, but the documentation page that you are looking for was not found.

\n\n

Documentation changes over time, and pages are moved around. We try to redirect you to the updated content where possible, but unfortunately, that didn\'t work this time (maybe because the content you were looking for does not exist in this version of the documentation).

\n

You can try to use the navigation to locate the content you\'re looking for, or search for a similar page.

\n', + 'mattermost': '', + 'matrix': '', + + 'github_url': 'https://github.com/canonical/microcloud', + 'repo_default_branch': 'main', + 'repo_folder': '/doc/', + + # Required for feedback button + 'github_issues': 'enabled', + + # Enables listing contributors on individual pages + # This feature is deprecated and will be removed in the future + 'display_contributors': False, + + 'sequential_nav': "both", } -# Default image for OGP (to prevent font errors, see -# https://github.com/canonical/sphinx-docs-starter-pack/pull/54 ) -if not 'ogp_image' in locals(): - ogp_image = 'https://assets.ubuntu.com/v1/253da317-image-document-ubuntudocs.svg' +# Enables the pencil icon to edit pages on GitHub, shown at the top of each page +html_theme_options = { + 'source_edit_link': html_context['github_url'] +} -############################################################ -### General configuration -############################################################ +# Project slug +# Required if your project is hosted on documentation.ubuntu.com +slug = "microcloud" + +####################### +# Sitemap configuration: https://sphinx-sitemap.readthedocs.io/ +####################### + +# sphinx-sitemap uses html_baseurl (set earlier in this file) to generate the full URL for each page: + +sitemap_url_scheme = '{link}' + +# Include `lastmod` dates in the sitemap: +sitemap_show_lastmod = True + +# Exclude generated pages from the sitemap: +sitemap_excludes = [ + '404/', + 'genindex/', + 'search/', +] + +# Add more pages to sitemap_excludes if needed. Wildcards are supported. +# For example, to exclude module pages generated by autodoc, add '_modules/*'. + +####################### +# Template and asset locations +####################### + +html_static_path = ['.sphinx/_static', '_static'] + + +############# +# Redirects # +############# + +# minae: Redirects is imported from redirects.py + +########################### +# Link checker exceptions # +########################### + +# Always ignore these links +linkcheck_ignore = [ + 'http://127.0.0.1:8000', + 'http://localhost:8000', + # These links may fail from time to time + 'https://ceph.io', + # Cloudflare protection on SourceForge domains often block linkcheck + r"https://.*\.sourceforge\.(net|io)/.*", + # Ignore so that we can link change log in release notes before a release is ready + r"https://github\.com/canonical/microcloud/compare.*", +] + +# Pages on which to ignore anchors (check the link without the anchor) +linkcheck_anchors_ignore_for_url = [ + r'https://snapcraft\.io/docs/.*', + r'https://github\.com/.*', + r'https://charmhub\.io/.*', +] + +# Increase linkcheck rate limit timeout max, default when unset is 300 +# https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-linkcheck_timeout +linkcheck_rate_limit_timeout = 600 +# Increase linkcheck retries, default when unset is 1 +# https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-linkcheck_retries +linkcheck_retries = 3 + +# Increase the duration, in seconds, that the linkcheck builder will wait for a response after each hyperlink request. +# Default when unset is 30 +# https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-linkcheck_timeout +linkcheck_timeout = 45 + + +######################## +# Configuration extras # +######################## + +# Additional MyST extensions, if any +myst_enable_extensions = [ + 'substitution', + 'deflist', + 'linkify' +] + +extensions = [ + 'sphinx_design', + 'sphinx_copybutton', + 'sphinxcontrib.jquery', + 'sphinx_reredirects', + 'myst_parser', + 'sphinxext.opengraph', + 'sphinx_tabs.tabs', + 'canonical.youtube-links', + 'canonical.related-links', + 'canonical.custom-rst-roles', + 'canonical.terminal-output', + 'notfound.extension', + 'sphinx.ext.intersphinx', + 'sphinx_sitemap', +] + +# Excludes files or directories from processing exclude_patterns = [ '_build', 'Thumbs.db', '.DS_Store', '.sphinx', + 'reference/release-notes/release-notes-template.md', + "integration", + 'README.md', ] -exclude_patterns.extend(custom_excludes) -rst_epilog = ''' -.. include:: /reuse/links.txt -''' -if 'custom_rst_epilog' in locals(): - rst_epilog = custom_rst_epilog +html_css_files = [ + 'custom.css', + 'header.css', + 'github_issue_links.css', + 'furo_colors.css', + 'footer.css', + 'https://assets.ubuntu.com/v1/d86746ef-cookie_banner.css', +] -source_suffix = { - '.rst': 'restructuredtext', - '.md': 'markdown', -} +html_js_files = [ + 'header-nav.js', + 'footer.js', + 'https://assets.ubuntu.com/v1/287a5e8f-bundle.js', + 'rtd-versions-flyout.js', + 'github_issue_links.js', +] -if not 'conf_py_path' in html_context and 'github_folder' in html_context: - html_context['conf_py_path'] = html_context['github_folder'] +# Feedback button at the top; enabled by default +# To disable the button, uncomment the line below: -# For ignoring specific links -linkcheck_anchors_ignore_for_url = [ - r'https://github\.com/.*' -] -linkcheck_anchors_ignore_for_url.extend(custom_linkcheck_anchors_ignore_for_url) +# disable_feedback_button = True -# Tags cannot be added directly in custom_conf.py, so add them here -for tag in custom_tags: - tags.add(tag) +# Define a :center: role that can be used to center the content of table cells. +rst_prolog = ''' +.. role:: center + :class: align-center +''' -# html_context['get_contribs'] is a function and cannot be -# cached (see https://github.com/sphinx-doc/sphinx/issues/12300) -suppress_warnings = ["config.cache"] +# Load substitutions from YAML file +if os.path.exists('./substitutions.yaml'): + with open('./substitutions.yaml', 'r') as fd: + myst_substitutions = yaml.safe_load(fd.read()) ############################################################ ### Styling @@ -130,8 +236,8 @@ # Setting templates_path for epub makes the build fail if builder == 'dirhtml' or builder == 'html': templates_path = ['.sphinx/_templates'] - if 'custom_templates_path' in globals(): - templates_path = custom_templates_path + templates_path + if os.environ.get('SINGLE_BUILD') != 'True': + templates_path.insert(0, 'integration/microcloud/_templates') notfound_template = '404.html' # Theme configuration @@ -144,62 +250,58 @@ 'sidebar_hide_name': True } -############################################################ -### Additional files -############################################################ +########################################## +### Misc MicroCloud custom configuration # +########################################## + +# Use custom 404 page text +notfound_context = { + 'title': 'Page not found', + 'body': '

Sorry, but the documentation page that you are looking for was not found.

\n\n

Documentation changes over time, and pages are moved around. We try to redirect you to the updated content where possible, but unfortunately, that didn\'t work this time (maybe because the content you were looking for does not exist in this version of the documentation).

\n

You can try to use the navigation to locate the content you\'re looking for, or search for a similar page.

\n', +} -html_static_path = ['.sphinx/_static'] -if 'custom_html_static_path' in globals(): - html_static_path = html_static_path + custom_html_static_path +# Intersphinx setup differs for different builds to optimize use with integrated docs +if ('SINGLE_BUILD' in os.environ and os.environ['SINGLE_BUILD'] == 'True'): + intersphinx_mapping = { + 'lxd': ('https://documentation.ubuntu.com/lxd/stable-5.21/', None), + 'microceph': ('https://documentation.ubuntu.com/canonical-microceph/v19.2.0-squid/', None), + 'microovn': ('https://canonical-microovn.readthedocs-hosted.com/en/24.03/', None), + } +elif ('READTHEDOCS' in os.environ) and (os.environ['READTHEDOCS'] == 'True'): + intersphinx_mapping = { + 'lxd': (os.environ['PATH_PREFIX'] + 'lxd/', os.environ['READTHEDOCS_OUTPUT'] + 'html/lxd/objects.inv'), + 'microceph': (os.environ['PATH_PREFIX'] + 'microceph/', os.environ['READTHEDOCS_OUTPUT'] + 'html/microceph/objects.inv'), + 'microovn': (os.environ['PATH_PREFIX'] + 'microovn/', os.environ['READTHEDOCS_OUTPUT'] + 'html/microovn/objects.inv'), + } +else: + intersphinx_mapping = { + 'lxd': ('/lxd/', '_build/lxd/objects.inv'), + 'microceph': ('/microceph/', '_build/microceph/objects.inv'), + 'microovn': ('/microovn/', '_build/microovn/objects.inv'), + } -html_css_files = [ - 'custom.css', - 'header.css', - 'github_issue_links.css', - 'furo_colors.css', - 'footer.css' -] -html_css_files.extend(custom_html_css_files) - -html_js_files = ['header-nav.js', 'footer.js'] -if 'github_issues' in html_context and html_context['github_issues'] and not disable_feedback_button: - html_js_files.append('github_issue_links.js') -html_js_files.extend(custom_html_js_files) - -############################################################# -# Display the contributors - -def get_contributors_for_file(github_url, github_folder, pagename, page_source_suffix, display_contributors_since=None): - filename = f"{pagename}{page_source_suffix}" - paths=html_context['github_folder'][1:] + filename - - try: - repo = Repo(".") - except InvalidGitRepositoryError: - cwd = os.getcwd() - ghfolder = html_context['github_folder'][:-1] - if ghfolder and cwd.endswith(ghfolder): - repo = Repo(cwd.rpartition(ghfolder)[0]) - else: - print("The local Git repository could not be found.") - return - - since = display_contributors_since if display_contributors_since and display_contributors_since.strip() else None - - commits = repo.iter_commits(paths=paths, since=since) - - contributors_dict = {} - for commit in commits: - contributor = commit.author.name - if contributor not in contributors_dict or commit.committed_date > contributors_dict[contributor]['date']: - contributors_dict[contributor] = { - 'date': commit.committed_date, - 'sha': commit.hexsha - } - # The github_page contains the link to the contributor's latest commit. - contributors_list = [{'name': name, 'github_page': f"{github_url}/commit/{data['sha']}"} for name, data in contributors_dict.items()] - sorted_contributors_list = sorted(contributors_list, key=lambda x: x['name']) - return sorted_contributors_list - -html_context['get_contribs'] = get_contributors_for_file -############################################################# +# Add intersphinx mappings for docs sets not part of the MicroCloud integrated docs here: + +base_intersphinx = { + 'ceph': ('https://docs.ceph.com/en/latest/', None), + 'snap': ('https://snapcraft.io/docs/', None), +} + +intersphinx_mapping.update(base_intersphinx) + +# Update html_context for integrated builds and add the "integrated" tag +if os.environ.get('SINGLE_BUILD') != 'True': + exec(compile(source=open('.sphinx/_integration/add_config.py').read(), filename='.sphinx/_integration/add_config.py', mode='exec')) + # MicroCloud docs are at the URL root, so override the relative paths to sibling doc sets + html_context['lxd_path'] = "lxd" + html_context['lxd_tag'] = "lxd/_static/tag.png" + html_context['microceph_path'] = "microceph" + html_context['microceph_tag'] = "microceph/_static/tag.png" + html_context['microovn_path'] = "microovn" + html_context['microovn_tag'] = "microovn/_static/microovn.png" + html_static_path.append('integration/microcloud/_static') + tags.add('integrated') + +# Version label shown in the RTD flyout next to "default", in parentheses. +# Set the FLYOUT_DEFAULT_VERSION_LABEL environment variable in the RTD project dashboard. +html_context['flyout_default_version_label'] = os.environ.get('FLYOUT_DEFAULT_VERSION_LABEL', '') diff --git a/doc/custom_conf.py b/doc/custom_conf.py deleted file mode 100644 index 02f54226c..000000000 --- a/doc/custom_conf.py +++ /dev/null @@ -1,331 +0,0 @@ -import datetime -import os -import re -import yaml -from redirects import redirects - -# Custom configuration for the Sphinx documentation builder. -# All configuration specific to your project should be done in this file. -# -# The file is included in the common conf.py configuration file. -# You can modify any of the settings below or add any configuration that -# is not covered by the common conf.py file. -# -# For the full list of built-in configuration values, see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html -# -# If you're not familiar with Sphinx and don't want to use advanced -# features, it is sufficient to update the settings in the "Project -# information" section. - -############################################################ -### Project information -############################################################ - -# Product name -project = 'MicroCloud' -author = 'Canonical Group Ltd' - -with open('../version/version.go') as f: - match = re.search(r'RawVersion = "([^"]+)"', f.read()) - version = match.group(1) if match else '' - -# Sidebar documentation title; best kept reasonably short -# To disable the title, set to an empty string. -html_title = project + ' documentation ' + version - -# The default value uses the current year as the copyright year. -# -# For static works, it is common to provide the year of first publication. -# Another option is to give the first year and the current year -# for documentation that is often changed, e.g. 2022–2023 (note the en-dash). -# -# A way to check a GitHub repo's creation date is to obtain a classic GitHub -# token with 'repo' permissions here: https://github.com/settings/tokens -# Next, use 'curl' and 'jq' to extract the date from the GitHub API's output: -# -# curl -H 'Authorization: token ' \ -# -H 'Accept: application/vnd.github.v3.raw' \ -# https://api.github.com/repos/canonical/ | jq '.created_at' - -copyright = '%s, %s' % (datetime.date.today().year, author) - -## Open Graph configuration - defines what is displayed as a link preview -## when linking to the documentation from another website (see https://ogp.me/) -# The URL where the documentation will be hosted (leave empty if you -# don't know yet) -# NOTE: If no ogp_* variable is defined (e.g. if you remove this section) the -# sphinxext.opengraph extension will be disabled. -ogp_site_url = 'https://documentation.ubuntu.com/microcloud/' -# The documentation website name (usually the same as the product name) -ogp_site_name = project -# The URL of an image or logo that is used in the preview -ogp_image = 'https://assets.ubuntu.com/v1/d53eeeac-Microcloud_favicon_64px_v2.png' - -# Update with the local path to the favicon for your product -# (default is the circle of friends) -html_favicon = '.sphinx/_static/favicon.png' - -# (Some settings must be part of the html_context dictionary, while others -# are on root level. Don't move the settings.) -html_context = { - - # Change to the link to the website of your product (without "https://") - # For example: "ubuntu.com/lxd" or "microcloud.is" - # If there is no product website, edit the header template to remove the - # link (see the readme for instructions). - 'product_page': 'canonical.com/microcloud', - - # Add your product tag (the orange part of your logo, will be used in the - # header) to ".sphinx/_static" and change the path here (start with "_static") - # (default is the circle of friends) - 'product_tag': '_static/tag.png', - - # Change to the discourse instance you want to be able to link to - # using the :discourse: metadata at the top of a file - # (use an empty value if you don't want to link) - 'discourse': 'https://discourse.ubuntu.com/c/lxd/microcloud/', - - # ru-fu: we're using different Discourses - 'discourse_prefix': { - 'ubuntu': 'https://discourse.ubuntu.com/t/', - 'lxc': 'https://discuss.linuxcontainers.org/t/', - }, - - # Change to the Mattermost channel you want to link to - # (use an empty value if you don't want to link) - 'mattermost': '', - - # Change to the Matrix channel you want to link to - # (use an empty value if you don't want to link) - 'matrix': '', - - # Change to the GitHub URL for your project - # This is used, for example, to link to the source files and allow creating GitHub issues directly from the documentation. - 'github_url': 'https://github.com/canonical/microcloud', - - # Change to the branch for this version of the documentation - 'github_version': 'main', - - # Change to the folder that contains the documentation - # (usually "/" or "/docs/") - 'github_folder': '/doc/', - - # Change to an empty value if your GitHub repo doesn't have issues enabled. - # This will disable the feedback button and the issue link in the footer. - 'github_issues': 'enabled', - - # Controls the existence of Previous / Next buttons at the bottom of pages - # Valid options: none, prev, next, both - 'sequential_nav': "both", - - # Controls if to display the contributors of a file or not - "display_contributors": True, - - # Controls time frame for showing the contributors - "display_contributors_since": "" -} - -# If your project is on documentation.ubuntu.com, specify the project -# slug (for example, "lxd") here. -slug = "microcloud" - -####################### -# Sitemap configuration: https://sphinx-sitemap.readthedocs.io/ -####################### - -# Base URL of RTD hosted project - -html_baseurl = 'https://documentation.ubuntu.com/microcloud/' - -# Configures URL scheme for sphinx-sitemap to generate correct URLs -# based on the version if built in RTD -if 'READTHEDOCS_VERSION' in os.environ: - rtd_version = os.environ["READTHEDOCS_VERSION"] - sitemap_url_scheme = f'{rtd_version}/{{link}}' -else: - sitemap_url_scheme = '{link}' - -############################################################ -### Redirects -############################################################ - -# Set up redirects (https://documatt.gitlab.io/sphinx-reredirects/usage.html) -# For example: 'explanation/old-name.html': '../how-to/prettify.html', -# You can also configure redirects in the Read the Docs project dashboard -# (see https://docs.readthedocs.io/en/stable/guides/redirects.html). -# NOTE: If this variable is not defined, set to None, or the dictionary is empty, -# the sphinx_reredirects extension will be disabled. -# minae: Redirects is imported from redirects.py - -############################################################ -### Link checker -############################################################ - -# Links to ignore when checking links -linkcheck_ignore = [ - 'http://127.0.0.1:8000', - 'http://localhost:8000', - # These links may fail from time to time - 'https://ceph.io', - # Cloudflare protection on SourceForge domains often block linkcheck - r"https://.*\.sourceforge\.(net|io)/.*", - # Ignore so that we can link change log in release notes before a release is ready - r"https://github\.com/canonical/microcloud/compare.*", - ] - -# Pages on which to ignore anchors -# (This list will be appended to linkcheck_anchors_ignore_for_url) - -custom_linkcheck_anchors_ignore_for_url = [ - r'https://snapcraft\.io/docs/.*' - ] - -# Increase linkcheck rate limit timeout max, default when unset is 300 -# https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-linkcheck_timeout -linkcheck_rate_limit_timeout = 600 - -# Increase linkcheck retries, default when unset is 1 -# https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-linkcheck_retries -linkcheck_retries = 3 - -# Increase the duration, in seconds, that the linkcheck builder will wait for a response after each hyperlink request. -# Default when unset is 30 -# https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-linkcheck_timeout -linkcheck_timeout = 45 - -############################################################ -### Additions to default configuration -############################################################ - -## The following settings are appended to the default configuration. -## Use them to extend the default functionality. - -# Remove this variable to disable the MyST parser extensions. -custom_myst_extensions = [] - -# Add custom Sphinx extensions as needed. -# This array contains recommended extensions that should be used. -# NOTE: The following extensions are handled automatically and do -# not need to be added here: myst_parser, sphinx_copybutton, sphinx_design, -# sphinx_reredirects, sphinxcontrib.jquery, sphinxext.opengraph -custom_extensions = [ - 'sphinx_tabs.tabs', - 'canonical.youtube-links', - 'canonical.related-links', - 'canonical.custom-rst-roles', - 'canonical.terminal-output', - 'notfound.extension', - 'sphinx.ext.intersphinx', - 'sphinx_sitemap', - ] - -# Add custom required Python modules that must be added to the -# .sphinx/requirements.txt file. -# NOTE: The following modules are handled automatically and do not need to be -# added here: canonical-sphinx-extensions, furo, linkify-it-py, myst-parser, -# pyspelling, sphinx, sphinx-autobuild, sphinx-copybutton, sphinx-design, -# sphinx-notfound-page, sphinx-reredirects, sphinx-tabs, sphinxcontrib-jquery, -# sphinxext-opengraph -custom_required_modules = [ - 'sphinx-sitemap', - 'pyyaml', -] - -# Add files or directories that should be excluded from processing. -custom_excludes = [ - "integration", - 'README.md' - ] - -# Add CSS files (located in .sphinx/_static/ or from external link) -custom_html_css_files = [ - 'https://assets.ubuntu.com/v1/d86746ef-cookie_banner.css', -] - -# Add JavaScript files (located in .sphinx/_static/ or from external link) -custom_html_js_files = [ - 'https://assets.ubuntu.com/v1/287a5e8f-bundle.js', - 'rtd-versions-flyout.js', -] - -## The following settings override the default configuration. - -# Specify a reST string that is included at the end of each file. -# If commented out, use the default (which pulls the reuse/links.txt -# file into each reST file). -# custom_rst_epilog = '' - -# By default, the documentation includes a feedback button at the top. -# You can disable it by setting the following configuration to True. -disable_feedback_button = False - -# Add tags that you want to use for conditional inclusion of text -# (https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#tags) -custom_tags = [] - -# If you are using the :manpage: role, set this variable to the URL for the version -# that you want to link to: -# manpages_url = "https://manpages.ubuntu.com/manpages/noble/en/man{section}/{page}.{section}.html" - -############################################################ -### Additional configuration -############################################################ - -## Add any configuration that is not covered by the common conf.py file. - -if ('SINGLE_BUILD' in os.environ and os.environ['SINGLE_BUILD'] == 'True'): - intersphinx_mapping = { - 'lxd': ('https://documentation.ubuntu.com/lxd/stable-5.21/', None), - 'microceph': ('https://documentation.ubuntu.com/canonical-microceph/v19.2.0-squid/', None), - 'microovn': ('https://canonical-microovn.readthedocs-hosted.com/en/24.03/', None), - } -elif ('READTHEDOCS' in os.environ) and (os.environ['READTHEDOCS'] == 'True'): - intersphinx_mapping = { - 'lxd': (os.environ['PATH_PREFIX'] + 'lxd/', os.environ['READTHEDOCS_OUTPUT'] + 'html/lxd/objects.inv'), - 'microceph': (os.environ['PATH_PREFIX'] + 'microceph/', os.environ['READTHEDOCS_OUTPUT'] + 'html/microceph/objects.inv'), - 'microovn': (os.environ['PATH_PREFIX'] + 'microovn/', os.environ['READTHEDOCS_OUTPUT'] + 'html/microovn/objects.inv'), - } -else: - intersphinx_mapping = { - 'lxd': ('/lxd/', '_build/lxd/objects.inv'), - 'microceph': ('/microceph/', '_build/microceph/objects.inv'), - 'microovn': ('/microovn/', '_build/microovn/objects.inv'), - } - -# Add intersphinx mappings for docs sets not part of the MicroCloud integrated docs here: - -base_intersphinx = { - 'ceph': ('https://docs.ceph.com/en/latest/', None), - 'snap': ('https://snapcraft.io/docs/', None), -} - -intersphinx_mapping.update(base_intersphinx) - -# Define a :center: role that can be used to center the content of table cells. -rst_prolog = ''' -.. role:: center - :class: align-center -''' - -if not ('SINGLE_BUILD' in os.environ and os.environ['SINGLE_BUILD'] == 'True'): - exec(compile(source=open('.sphinx/_integration/add_config.py').read(), filename='.sphinx/_integration/add_config.py', mode='exec')) - # MicroCloud docs are at the URL root, so override the relative paths to sibling doc sets - html_context['lxd_path'] = "lxd" - html_context['lxd_tag'] = "lxd/_static/tag.png" - html_context['microceph_path'] = "microceph" - html_context['microceph_tag'] = "microceph/_static/tag.png" - html_context['microovn_path'] = "microovn" - html_context['microovn_tag'] = "microovn/_static/microovn.png" - custom_html_static_path = ['integration/microcloud/_static'] - custom_templates_path = ['integration/microcloud/_templates'] - custom_tags.append('integrated') - -# Load substitutions from YAML file -if os.path.exists('./substitutions.yaml'): - with open('./substitutions.yaml', 'r') as fd: - myst_substitutions = yaml.safe_load(fd.read()) - -# Version label shown in the RTD flyout next to "default", in parentheses. -# Set the FLYOUT_DEFAULT_VERSION_LABEL environment variable in the RTD project dashboard. -html_context['flyout_default_version_label'] = os.environ.get('FLYOUT_DEFAULT_VERSION_LABEL', '') From 39a0f68785de53184aa8dc31cc52d156b150e212 Mon Sep 17 00:00:00 2001 From: Minae Lee Date: Mon, 4 May 2026 14:03:25 -0700 Subject: [PATCH 10/26] doc: merge and update makefile Merge Makefile.sp into Makefile and update Makefile to better align with the Sphinx Stack (formerly the Sphinx Starter Pack). Signed-off-by: Minae Lee (cherry picked from commit 9dce710f8946284d0d3d333c9f4bd5f898f3bb7c) --- doc/.gitignore | 2 +- doc/.readthedocs.yaml | 2 +- doc/Makefile | 187 +++++++++++++++++++++++++++++------------- doc/Makefile.sp | 109 ------------------------ doc/conf.py | 1 + 5 files changed, 131 insertions(+), 170 deletions(-) delete mode 100644 doc/Makefile.sp diff --git a/doc/.gitignore b/doc/.gitignore index 1d39bb85b..7d7ee7b55 100644 --- a/doc/.gitignore +++ b/doc/.gitignore @@ -1,5 +1,5 @@ /*env*/ -.sphinx/venv/ +.venv/ .sphinx/warnings.txt .sphinx/.wordlist.dic .sphinx/.doctrees/ diff --git a/doc/.readthedocs.yaml b/doc/.readthedocs.yaml index 1796093af..20abf42cf 100644 --- a/doc/.readthedocs.yaml +++ b/doc/.readthedocs.yaml @@ -20,7 +20,7 @@ build: # and https://github.com/canonical/microceph/pull/400 is restored) - ln -s /bin/true doc/integration/microovn/docs/woke - ln -s /bin/true doc/integration/microceph/docs/woke - - make GOTOOLCHAIN=auto doc-html-rtd PATH=$PATH:. + - cd doc && make GOTOOLCHAIN=auto html-rtd PATH=$PATH:. # Build documentation in the docs/ directory with Sphinx sphinx: diff --git a/doc/Makefile b/doc/Makefile index 416a9ad35..d2100ef91 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -1,12 +1,3 @@ -# This Makefile stub allows you to customize starter pack (SP) targets. -# Consider this file as a bridge between your project -# and the starter pack's predefined targets that reside in Makefile.sp. -# -# You can add your own, non-SP targets here or override SP targets -# to fit your project's needs. For example, you can define and use targets -# named "install" or "run", but continue to use SP targets like "sp-install" -# or "sp-run" when working on the documentation. - current_dir := $(dir $(abspath $(firstword $(MAKEFILE_LIST)))) # Set the path prefix and MicroCloud component versions corresponding to each MicroCloud docs version. @@ -16,30 +7,78 @@ MICROCEPHVERSION = 64d02d9538a89be039707ecbf942ca1aeae29760 # origin/main. MICROOVNVERSION = origin/branch-24.03 SPHINX_DIR ?= .sphinx -DOCS_SOURCEDIR ?= . -DOCS_VENVDIR ?= $(SPHINX_DIR)/venv +SPHINX_OPTS ?= -c . -d $(SPHINX_DIR)/.doctrees -j auto +SPHINX_BUILD ?= $(DOCS_VENVDIR)/bin/sphinx-build +SPHINX_HOST ?= 127.0.0.1 +SPHINX_PORT ?= 8000 +DOCS_VENVDIR ?= .venv DOCS_VENV ?= $(DOCS_VENVDIR)/bin/activate -INTEGRATION_DIR ?= integration +DOCS_SOURCEDIR ?= . +DOCS_BUILDDIR ?= _build + +PA11Y_CMD ?= $(SPHINX_DIR)/node_modules/pa11y/bin/pa11y.js --config $(SPHINX_DIR)/pa11y.json +TARGET = * +ALLFILES = *.rst **/*.rst +INTEGRATION_DIR ?= integration # Put it first so that "make" without argument is like "make help". help: - @echo "\n" \ - "------------------------------------------------------------- \n" \ - "* watch, build and serve the documentation: make run \n" \ - "* only build: make html \n" \ - "* only serve: make serve \n" \ - "* clean built doc files: make clean-doc \n" \ - "* clean full environment: make clean \n" \ - "* check links: make linkcheck \n" \ - "* check spelling: make spelling \n" \ - "* check spelling (without building again): make spellcheck \n" \ - "* check inclusive language: make woke \n" \ - "* check accessibility: make pa11y \n" \ - "* check style guide compliance: make vale \n" \ - "* check style guide compliance on target: make vale TARGET=* \n" \ - "* check markdown: make lint-md \n" \ - "* other possible targets: make \n" \ - "------------------------------------------------------------- \n" + @echo + @echo "-------------------------------------------------------------" + @echo "* watch, build and serve the documentation: make run" + @echo "* only build: make html" + @echo "* only serve: make serve" + @echo "* clean built doc files: make clean-doc" + @echo "* clean full environment: make clean" + @echo "* check links: make linkcheck" + @echo "* check markdown: make lint-md" + @echo "* check spelling: make spelling" + @echo "* check spelling (without building again): make spellcheck" + @echo "* check inclusive language: make woke" + @echo "* check accessibility: make pa11y" + @echo "* check style guide compliance: make vale" + @echo "* check style guide compliance on target: make vale TARGET=*" + @echo "* other possible targets: make " + @echo "-------------------------------------------------------------" + @echo + +.PHONY: help full-help html epub linkcheck spelling spellcheck woke \ + vale pa11y run serve install pa11y-install \ + clean clean-doc lint-md lint \ + integrate clean-integrate html html-rtd microcloud \ + serve-microcloud woke-install pymarkdownlnt-install + +full-help: $(DOCS_VENVDIR) + @. $(DOCS_VENV); $(SPHINX_BUILD) -M help "$(DOCS_SOURCEDIR)" "$(DOCS_BUILDDIR)" $(SPHINX_OPTS) $(O) + @echo "\n\033[1;31mNOTE: This help texts shows unsupported targets!\033[0m" + @echo "Run 'make help' to see supported targets." + +# If requirements are updated, venv should be rebuilt and timestamped. +$(DOCS_VENVDIR): + @echo "... setting up virtualenv" + python3 -m venv $(DOCS_VENVDIR) || { echo "You must install python3-venv before you can build the documentation."; exit 1; } + . $(DOCS_VENV); pip install $(PIPOPTS) --require-virtualenv \ + --upgrade -r requirements.txt \ + --log $(DOCS_VENVDIR)/pip_install.log + @test ! -f $(DOCS_VENVDIR)/pip_list.txt || \ + mv $(DOCS_VENVDIR)/pip_list.txt $(DOCS_VENVDIR)/pip_list.txt.bak + @. $(DOCS_VENV); pip list --local --format=freeze > $(DOCS_VENVDIR)/pip_list.txt + @touch $(DOCS_VENVDIR) + +pa11y-install: + @command -v $(PA11Y_CMD) >/dev/null || { \ + echo "Installing \"pa11y\" from npm..."; echo; \ + mkdir -p $(SPHINX_DIR)/node_modules/ ; \ + npm install --prefix $(SPHINX_DIR) pa11y; \ + } + +pymarkdownlnt-install: install + @. $(DOCS_VENV); test -d $(DOCS_VENVDIR)/lib/python*/site-packages/pymarkdown || pip install pymarkdownlnt==0.9.35 + +install: $(DOCS_VENVDIR) + +run: install + . $(DOCS_VENV); $(DOCS_VENVDIR)/bin/sphinx-autobuild -b dirhtml --host $(SPHINX_HOST) --port $(SPHINX_PORT) "$(DOCS_SOURCEDIR)" "$(DOCS_BUILDDIR)" $(SPHINX_OPTS) integrate: # Pull the other repositories @@ -75,52 +114,59 @@ integrate: # Override the MicroOVN tag with the circle of friends one (for consistency) cp .sphinx/_integration/tag.png integration/microovn/docs/.sphinx/_static/microovn.png -clean-integrate: - rm -rf integration/lxd - rm -rf integration/microceph - rm -rf integration/microovn - -clean: clean-integrate - $(MAKE) -f Makefile.sp sp-clean - # `html` builds the integrated docs. -html: integrate +html: integrate install mkdir -p $(current_dir)/_build cd integration/lxd/doc/ && $(MAKE) html BUILDDIR=$(current_dir)/_build/lxd cd integration/microceph/docs/ && $(MAKE) html BUILDDIR=$(current_dir)/_build/microceph cd integration/microovn/docs/ && $(MAKE) html BUILDDIR=$(current_dir)/_build/microovn - $(MAKE) -f Makefile.sp sp-html BUILDDIR=$(current_dir)/_build ADDPREREQS='gitpython pyyaml' + . $(DOCS_VENV); $(SPHINX_BUILD) -W --keep-going -b dirhtml "$(DOCS_SOURCEDIR)" "$(current_dir)/_build" -w $(SPHINX_DIR)/warnings.txt $(SPHINX_OPTS) # `html-rtd` builds the integrated docs, with the correct paths for Read the Docs. # This target is used by the Read the Docs build. -html-rtd: +html-rtd: install PATH_PREFIX=$(PATH_PREFIX) $(MAKE) -C integration/lxd/doc/ html-rtd BUILDDIR=$(READTHEDOCS_OUTPUT)/html/lxd PATH_PREFIX=$(PATH_PREFIX) $(MAKE) -C integration/microceph/docs/ html BUILDDIR=$(READTHEDOCS_OUTPUT)/html/microceph PATH_PREFIX=$(PATH_PREFIX) $(MAKE) -C integration/microovn/docs/ html BUILDDIR=$(READTHEDOCS_OUTPUT)/html/microovn - ADDPREREQS='gitpython pyyaml' PATH_PREFIX=$(PATH_PREFIX) $(MAKE) -f Makefile.sp sp-html BUILDDIR=$(READTHEDOCS_OUTPUT)/html + . $(DOCS_VENV); PATH_PREFIX=$(PATH_PREFIX) $(SPHINX_BUILD) -W --keep-going -b dirhtml "$(DOCS_SOURCEDIR)" "$(READTHEDOCS_OUTPUT)/html" -w $(SPHINX_DIR)/warnings.txt $(SPHINX_OPTS) -# `spelling` checks only the MicroCloud docs. -spelling: clean-doc microcloud - $(MAKE) -f Makefile.sp sp-spellcheck +epub: install + . $(DOCS_VENV); $(SPHINX_BUILD) -b epub "$(DOCS_SOURCEDIR)" "$(DOCS_BUILDDIR)" -w $(SPHINX_DIR)/warnings.txt $(SPHINX_OPTS) # `microcloud` builds only the MicroCloud docs, as a stand-alone doc set. -microcloud: - $(MAKE) -f Makefile.sp sp-html SINGLE_BUILD=True - -.PHONY: run -run: - $(MAKE) -f Makefile.sp sp-run LOCAL_SPHINX_BUILD=True ADDPREREQS='gitpython pyyaml' SPHINXOPTS="--ignore './index.html' -c . -d .sphinx/.doctrees -j auto" +microcloud: install + . $(DOCS_VENV); SINGLE_BUILD=True $(SPHINX_BUILD) -W --keep-going -b dirhtml "$(DOCS_SOURCEDIR)" "$(DOCS_BUILDDIR)" -w $(SPHINX_DIR)/warnings.txt $(SPHINX_OPTS) # `serve` rebuilds the integrated docs and serves them. serve: html - cd $(current_dir)/_build/; python3 -m http.server --bind 127.0.0.1 8000 + cd "$(DOCS_BUILDDIR)"; python3 -m http.server --bind $(SPHINX_HOST) $(SPHINX_PORT) -# `serve-microcloud` rebuilds the MicroCloud docs as a stand-along doc set and serves them. +# `serve-microcloud` rebuilds the MicroCloud docs as a stand-alone doc set and serves them. serve-microcloud: microcloud - cd $(current_dir)/_build/; python3 -m http.server --bind 127.0.0.1 8000 + cd "$(DOCS_BUILDDIR)"; python3 -m http.server --bind $(SPHINX_HOST) $(SPHINX_PORT) + +clean: clean-integrate clean-doc + @test ! -e "$(DOCS_VENVDIR)" -o -d "$(DOCS_VENVDIR)" -a "$(abspath $(DOCS_VENVDIR))" != "$(DOCS_VENVDIR)" + rm -rf $(DOCS_VENVDIR) + rm -rf $(SPHINX_DIR)/node_modules/ + rm -rf $(SPHINX_DIR)/styles + rm -rf $(SPHINX_DIR)/vale.ini + +clean-doc: + git clean -fx "$(DOCS_BUILDDIR)" + rm -rf $(SPHINX_DIR)/.doctrees + +clean-integrate: + rm -rf integration/lxd + rm -rf integration/microceph + rm -rf integration/microovn -pymarkdownlnt-install: install - @. $(DOCS_VENV); test -d $(DOCS_VENVDIR)/lib/python*/site-packages/pymarkdown || pip install pymarkdownlnt==0.9.35 +linkcheck: install + . $(DOCS_VENV) ; $(SPHINX_BUILD) -b linkcheck -q "$(DOCS_SOURCEDIR)" "$(DOCS_BUILDDIR)" $(SPHINX_OPTS) || { grep --color -F "[broken]" "$(DOCS_BUILDDIR)/output.txt"; exit 1; } + exit 0 + +pa11y: pa11y-install html + find $(DOCS_BUILDDIR) -name *.html -print0 | xargs -n 1 -0 $(PA11Y_CMD) # Without --return-code-scheme explicit, pymarkdownlnt returns 1 for multiple scenarios # By using the explicit scheme, it only returns 1 when no files are found, @@ -148,8 +194,31 @@ lint lint-md: pymarkdownlnt-install echo "Passed"; \ fi; -install: - $(MAKE) -f Makefile.sp sp-install ADDPREREQS='pyyaml' - +woke: woke-install + woke $(ALLFILES) --exit-1-on-failure \ + -c https://github.com/canonical/Inclusive-naming/raw/main/config.yml + +woke-install: + @type woke >/dev/null 2>&1 || \ + { echo "Installing \"woke\" snap... \n"; sudo snap install woke; } + +vale: install + @. $(DOCS_VENV); test -d $(DOCS_VENVDIR)/lib/python*/site-packages/vale || pip install vale + @. $(DOCS_VENV); test -f $(SPHINX_DIR)/vale.ini || python3 $(SPHINX_DIR)/get_vale_conf.py + @. $(DOCS_VENV); find $(DOCS_VENVDIR)/lib/python*/site-packages/vale/vale_bin -size 195c -exec vale --config "$(SPHINX_DIR)/vale.ini" $(TARGET) > /dev/null \; + @echo "" + @echo "Running Vale against $(TARGET). To change target set TARGET= with make command" + @echo "" + @. $(DOCS_VENV); vale --config "$(SPHINX_DIR)/vale.ini" --glob='*.{md,txt,rst}' $(TARGET) +# `spelling` checks only the MicroCloud docs. +spelling: clean-doc microcloud spellcheck + +spellcheck: install + . $(DOCS_VENV); python3 -m pyspelling -c $(SPHINX_DIR)/spellingcheck.yaml -j $(shell nproc) + + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINX_OPTS). %: - $(MAKE) -f Makefile.sp sp-$@ + $(MAKE) --no-print-directory install + . $(DOCS_VENV); $(SPHINX_BUILD) -M $@ "$(DOCS_SOURCEDIR)" "$(DOCS_BUILDDIR)" $(SPHINX_OPTS) $(O) diff --git a/doc/Makefile.sp b/doc/Makefile.sp deleted file mode 100644 index e258a8b66..000000000 --- a/doc/Makefile.sp +++ /dev/null @@ -1,109 +0,0 @@ -# Minimal makefile for Sphinx documentation -# -# `Makefile.sp` is from the Sphinx starter pack and should not be -# modified. -# Add your customisation to `Makefile` instead. - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXDIR = .sphinx -SPHINXOPTS ?= -c . -d $(SPHINXDIR)/.doctrees -j auto -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build -VENVDIR = $(SPHINXDIR)/venv -PA11Y = $(SPHINXDIR)/node_modules/pa11y/bin/pa11y.js --config $(SPHINXDIR)/pa11y.json -VENV = $(VENVDIR)/bin/activate -TARGET = * -ALLFILES = *.rst **/*.rst -ADDPREREQS ?= - -.PHONY: sp-full-help sp-woke-install sp-pa11y-install sp-install sp-run sp-html \ - sp-epub sp-serve sp-clean sp-clean-doc sp-spelling sp-spellcheck sp-linkcheck sp-woke \ - sp-pa11y Makefile.sp sp-vale - -sp-full-help: $(VENVDIR) - @. $(VENV); $(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - @echo "\n\033[1;31mNOTE: This help texts shows unsupported targets!\033[0m" - @echo "Run 'make help' to see supported targets." - -# If requirements are updated, venv should be rebuilt and timestamped. -$(VENVDIR): - @echo "... setting up virtualenv" - python3 -m venv $(VENVDIR) || { echo "You must install python3-venv before you can build the documentation."; exit 1; } - . $(VENV); pip install --require-virtualenv \ - --upgrade -r requirements.txt \ - --log $(VENVDIR)/pip_install.log - @test ! -f $(VENVDIR)/pip_list.txt || \ - mv $(VENVDIR)/pip_list.txt $(VENVDIR)/pip_list.txt.bak - @. $(VENV); pip list --local --format=freeze > $(VENVDIR)/pip_list.txt - @touch $(VENVDIR) - -sp-woke-install: - @type woke >/dev/null 2>&1 || \ - { echo "Installing \"woke\" snap... \n"; sudo snap install woke; } - -sp-pa11y-install: - @type $(PA11Y) >/dev/null 2>&1 || { \ - echo "Installing \"pa11y\" from npm... \n"; \ - mkdir -p $(SPHINXDIR)/node_modules/ ; \ - npm install --prefix $(SPHINXDIR) pa11y; \ - } - -sp-install: $(VENVDIR) - -sp-run: sp-install - . $(VENV); sphinx-autobuild -b dirhtml "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) - -# Doesn't depend on $(BUILDDIR) to rebuild properly at every run. -sp-html: sp-install - . $(VENV); $(SPHINXBUILD) -W --keep-going -b dirhtml "$(SOURCEDIR)" "$(BUILDDIR)" -w $(SPHINXDIR)/warnings.txt $(SPHINXOPTS) - -sp-epub: sp-install - . $(VENV); $(SPHINXBUILD) -b epub "$(SOURCEDIR)" "$(BUILDDIR)" -w $(SPHINXDIR)/warnings.txt $(SPHINXOPTS) - -sp-serve: sp-html - cd "$(BUILDDIR)"; python3 -m http.server --bind 127.0.0.1 8000 - -sp-clean: sp-clean-doc - @test ! -e "$(VENVDIR)" -o -d "$(VENVDIR)" -a "$(abspath $(VENVDIR))" != "$(VENVDIR)" - rm -rf $(VENVDIR) - rm -rf $(SPHINXDIR)/node_modules/ - rm -rf $(SPHINXDIR)/styles - rm -rf $(SPHINXDIR)/vale.ini - -sp-clean-doc: - git clean -fx "$(BUILDDIR)" - rm -rf $(SPHINXDIR)/.doctrees - -sp-spellcheck: - . $(VENV) ; python3 -m pyspelling -c $(SPHINXDIR)/spellingcheck.yaml -j $(shell nproc) - -sp-spelling: sp-html sp-spellcheck - -sp-linkcheck: sp-install - . $(VENV) ; $(SPHINXBUILD) -b linkcheck "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) || { grep --color -F "[broken]" "$(BUILDDIR)/output.txt"; exit 1; } - exit 0 - -sp-woke: sp-woke-install - woke $(ALLFILES) --exit-1-on-failure \ - -c https://github.com/canonical/Inclusive-naming/raw/main/config.yml - -sp-pa11y: sp-pa11y-install sp-html - find $(BUILDDIR) -name *.html -print0 | xargs -n 1 -0 $(PA11Y) - -sp-vale: sp-install - @. $(VENV); test -d $(SPHINXDIR)/venv/lib/python*/site-packages/vale || pip install vale - @. $(VENV); test -f $(SPHINXDIR)/vale.ini || python3 $(SPHINXDIR)/get_vale_conf.py - @. $(VENV); find $(SPHINXDIR)/venv/lib/python*/site-packages/vale/vale_bin -size 195c -exec vale --config "$(SPHINXDIR)/vale.ini" $(TARGET) > /dev/null \; - @echo "" - @echo "Running Vale against $(TARGET). To change target set TARGET= with make command" - @echo "" - @. $(VENV); vale --config "$(SPHINXDIR)/vale.ini" --glob='*.{md,txt,rst}' $(TARGET) - - - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile.sp - . $(VENV); $(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/doc/conf.py b/doc/conf.py index 9fd6df386..ba6d6c6d6 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -186,6 +186,7 @@ 'Thumbs.db', '.DS_Store', '.sphinx', + '.venv', 'reference/release-notes/release-notes-template.md', "integration", 'README.md', From fdedc05a0f404c6773aa8d2c15e9a1d508b5c840 Mon Sep 17 00:00:00 2001 From: Minae Lee Date: Mon, 4 May 2026 15:55:53 -0700 Subject: [PATCH 11/26] doc: replace pyspelling and woke with vale Signed-off-by: Minae Lee (cherry picked from commit 585a3ac675551309b9a68f3fb6504428fcd4c723) Amended to remove Swagger UI directories from `doc/.gitignore`, as this version does not use Swagger UI. Signed-off-by: Elijah Greenstein --- .wokeignore | 1 - doc/.gitignore | 1 - doc/.sphinx/get_vale_conf.py | 179 +++++++++++++++++++++++++++++---- doc/.sphinx/spellingcheck.yaml | 32 ------ doc/.wordlist.txt | 57 ----------- doc/Makefile | 71 +++++++------ doc/conf.py | 6 ++ doc/requirements.txt | 1 - 8 files changed, 206 insertions(+), 142 deletions(-) delete mode 120000 .wokeignore delete mode 100644 doc/.sphinx/spellingcheck.yaml delete mode 100644 doc/.wordlist.txt diff --git a/.wokeignore b/.wokeignore deleted file mode 120000 index 57c0c7b7e..000000000 --- a/.wokeignore +++ /dev/null @@ -1 +0,0 @@ -doc/.wokeignore \ No newline at end of file diff --git a/doc/.gitignore b/doc/.gitignore index 7d7ee7b55..c53cef1ea 100644 --- a/doc/.gitignore +++ b/doc/.gitignore @@ -1,7 +1,6 @@ /*env*/ .venv/ .sphinx/warnings.txt -.sphinx/.wordlist.dic .sphinx/.doctrees/ .sphinx/node_modules/ package*.json diff --git a/doc/.sphinx/get_vale_conf.py b/doc/.sphinx/get_vale_conf.py index 2f1c566f9..cebfa5a9d 100644 --- a/doc/.sphinx/get_vale_conf.py +++ b/doc/.sphinx/get_vale_conf.py @@ -1,29 +1,170 @@ -#! /usr/bin/env python +#!/usr/bin/env python3 -import requests import os +import shutil +import subprocess +import tempfile +import sys +import logging +import argparse -DIR=os.getcwd() +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' +) + +SPHINX_DIR = os.path.join(os.getcwd(), ".sphinx") + +GITHUB_REPO = "canonical/documentation-style-guide" +GITHUB_CLONE_URL = f"https://github.com/{GITHUB_REPO}.git" + +# Source paths to copy from repo +VALE_FILE_LIST = [ + "styles/Canonical", + "styles/config/vocabularies/Canonical", + "styles/config/dictionaries", + "vale.ini" +] + +def clone_repo_and_copy_paths(file_source_dest, overwrite=False): + """ + Clone the repository to a temporary directory and copy required files + + Args: + file_source_dest: dictionary of file paths to copy from the repository, + and their destination paths + overwrite: boolean flag to overwrite existing files in the destination + + Returns: + bool: Returns True only if all files were copied successfully. + Returns False if the input dictionary is empty, if the git clone fails, + or if any file fails to copy. + """ + + if not file_source_dest: + logging.error("No files to copy") + return False + + # Create temporary directory on disk for cloning + temp_dir = tempfile.mkdtemp() + logging.info("Cloning repository <%s> to temporary directory: %s", GITHUB_REPO, temp_dir) + clone_cmd = ["git", "clone", "--depth", "1", GITHUB_CLONE_URL, temp_dir] + + try: + result = subprocess.run( + clone_cmd, + capture_output=True, + text=True, + check=True + ) + logging.debug("Git clone output: %s", result.stdout) + + # Copy files from the cloned repository to the destination paths + is_copy_success = True + for source, dest in file_source_dest.items(): + source_path = os.path.join(temp_dir, source) + + if not copy_files_to_path(source_path, dest, overwrite): + is_copy_success = False + logging.error("Failed to copy %s to %s", source_path, dest) + + return is_copy_success + except subprocess.CalledProcessError as e: + logging.error("Git clone failed: %s", e.stderr) + return False + finally: + # Clean up temporary directory + logging.info("Cleaning up temporary directory: %s", temp_dir) + shutil.rmtree(temp_dir, ignore_errors=True) + +def copy_files_to_path(source_path, dest_path, overwrite=False): + """ + Copy a file or directory from source to destination + + Args: + source_path: Path to the source file or directory + dest_path: Path to the destination + overwrite: Boolean flag to overwrite existing files in the destination + + Returns: + bool: True if copy was successful, False otherwise + """ + # Skip if source file doesn't exist + if not os.path.exists(source_path): + logging.warning("Source path not found: %s", source_path) + return False + + logging.info("Copying %s to %s", source_path, dest_path) + # Handle existing files + if os.path.exists(dest_path): + if overwrite: + logging.info(" Destination exists, overwriting: %s", dest_path) + if os.path.isdir(dest_path): + shutil.rmtree(dest_path) + else: + os.remove(dest_path) + else: + logging.info(" Destination exists, skip copying (use overwrite=True to replace): %s", + dest_path) + return True # Skip copying + + # Create parent directory if it doesn't exist + parent_dir = os.path.dirname(dest_path) + if parent_dir: + os.makedirs(parent_dir, exist_ok=True) + + # Copy the source to destination + try: + if os.path.isdir(source_path): + # entire directory + shutil.copytree(source_path, dest_path) + else: + # individual files + shutil.copy2(source_path, dest_path) + return True + except (shutil.Error, OSError) as e: + logging.error("Copy failed: %s", e) + return False + +def parse_arguments(): + parser = argparse.ArgumentParser(description="Download Vale configuration files") + parser.add_argument("--no-overwrite", action="store_true", help="Don't overwrite existing files") + return parser.parse_args() def main(): + # Define local directory paths + vale_files_dict = {file: os.path.join(SPHINX_DIR, file) for file in VALE_FILE_LIST} + + # Parse command line arguments, default to overwrite_enabled = True + overwrite_enabled = not parse_arguments().no_overwrite + + # Clone repository to temporary directory and copy files to destination + if not clone_repo_and_copy_paths(vale_files_dict, overwrite=overwrite_enabled): + logging.error("Failed to download files from repository") + return 1 - if os.path.exists(f"{DIR}/.sphinx/styles/Canonical"): - print("Vale directory exists") - else: - os.makedirs(f"{DIR}/.sphinx/styles/Canonical") + # Replace the file type filter in vale.ini + vale_ini_path = os.path.join(SPHINX_DIR, "vale.ini") + try: + with open(vale_ini_path, 'r') as f: + content = f.read() + + # Replace the file type section + content = content.replace("[*.{md,txt,rst,html}]", "[*.{md}]") + + with open(vale_ini_path, 'w') as f: + f.write(content) + + logging.info("Updated vale.ini file type filter") + except (IOError, OSError) as e: + logging.error("Failed to update vale.ini: %s", e) + return 1 - url = "https://api.github.com/repos/canonical/praecepta/contents/styles/Canonical" - r = requests.get(url) - for item in r.json(): - download = requests.get(item["download_url"]) - file = open(".sphinx/styles/Canonical/" + item["name"], "w") - file.write(download.text) - file.close() + logging.info("Download complete") + return 0 - config = requests.get("https://raw.githubusercontent.com/canonical/praecepta/main/vale.ini") - file = open(".sphinx/vale.ini", "w") - file.write(config.text) - file.close() if __name__ == "__main__": - main() \ No newline at end of file + sys.exit(main()) # Keep return code \ No newline at end of file diff --git a/doc/.sphinx/spellingcheck.yaml b/doc/.sphinx/spellingcheck.yaml deleted file mode 100644 index f2f46553a..000000000 --- a/doc/.sphinx/spellingcheck.yaml +++ /dev/null @@ -1,32 +0,0 @@ -matrix: -- name: rST files - aspell: - lang: en - d: en_US - dictionary: - wordlists: - - .wordlist.txt - - .custom_wordlist.txt - output: .sphinx/.wordlist.dic - sources: - - _build/**/*.html - pipeline: - - pyspelling.filters.html: - comments: false - attributes: - - title - - alt - ignores: - - code - - pre - - spellexception - - .spellexception - - link - - title - - div.relatedlinks - - strong.command - - div.visually-hidden - - img - - a.p-navigation__link - - a.contributor - - a[title] diff --git a/doc/.wordlist.txt b/doc/.wordlist.txt deleted file mode 100644 index 7c0d2d077..000000000 --- a/doc/.wordlist.txt +++ /dev/null @@ -1,57 +0,0 @@ -# This wordlist is from the Sphinx starter pack and should not be -# modified. Add any custom terms to .custom_wordlist.txt instead. - -addons -API -APIs -balancer -Charmhub -CLI -Diátaxis -Dqlite -dropdown -EBS -EKS -enablement -favicon -Furo -Git -GitHub -Grafana -IAM -installable -JSON -Juju -Kubeflow -Kubernetes -Launchpad -linter -LTS -Makefile -Matrix -Mattermost -monmap -MyST -namespace -namespaces -NodePort -Numbat -observability -OEM -OIDC -OLM -Permalink -pre -Quickstart -ReadMe -reST -reStructuredText -RTD -subdirectories -subfolders -subtree -Ubuntu -UI -UUID -VM -YAML diff --git a/doc/Makefile b/doc/Makefile index d2100ef91..18c70d7b7 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -15,10 +15,11 @@ DOCS_VENVDIR ?= .venv DOCS_VENV ?= $(DOCS_VENVDIR)/bin/activate DOCS_SOURCEDIR ?= . DOCS_BUILDDIR ?= _build - +DOCS_VOCAB ?= $(SPHINX_DIR)/styles/config/vocabularies/Canonical +VALE_DIR ?= $(DOCS_VENVDIR)/lib/python*/site-packages/vale +VALE_CONFIG ?= $(SPHINX_DIR)/vale.ini PA11Y_CMD ?= $(SPHINX_DIR)/node_modules/pa11y/bin/pa11y.js --config $(SPHINX_DIR)/pa11y.json -TARGET = * -ALLFILES = *.rst **/*.rst +CHECK_PATH ?= $(filter-out $(DOCS_VENVDIR),$(wildcard *)) INTEGRATION_DIR ?= integration # Put it first so that "make" without argument is like "make help". @@ -37,16 +38,16 @@ help: @echo "* check inclusive language: make woke" @echo "* check accessibility: make pa11y" @echo "* check style guide compliance: make vale" - @echo "* check style guide compliance on target: make vale TARGET=*" + @echo "* check style guide compliance on target: make vale CHECK_PATH=*" @echo "* other possible targets: make " @echo "-------------------------------------------------------------" @echo .PHONY: help full-help html epub linkcheck spelling spellcheck woke \ - vale pa11y run serve install pa11y-install \ - clean clean-doc lint-md lint \ - integrate clean-integrate html html-rtd microcloud \ - serve-microcloud woke-install pymarkdownlnt-install + vale pa11y run serve install pa11y-install \ + vale-install clean clean-doc lint-md lint \ + integrate clean-integrate html html-rtd microcloud \ + serve-microcloud pymarkdownlnt-install full-help: $(DOCS_VENVDIR) @. $(DOCS_VENV); $(SPHINX_BUILD) -M help "$(DOCS_SOURCEDIR)" "$(DOCS_BUILDDIR)" $(SPHINX_OPTS) $(O) @@ -150,7 +151,7 @@ clean: clean-integrate clean-doc rm -rf $(DOCS_VENVDIR) rm -rf $(SPHINX_DIR)/node_modules/ rm -rf $(SPHINX_DIR)/styles - rm -rf $(SPHINX_DIR)/vale.ini + rm -rf $(VALE_CONFIG) clean-doc: git clean -fx "$(DOCS_BUILDDIR)" @@ -194,28 +195,36 @@ lint lint-md: pymarkdownlnt-install echo "Passed"; \ fi; -woke: woke-install - woke $(ALLFILES) --exit-1-on-failure \ - -c https://github.com/canonical/Inclusive-naming/raw/main/config.yml - -woke-install: - @type woke >/dev/null 2>&1 || \ - { echo "Installing \"woke\" snap... \n"; sudo snap install woke; } - -vale: install - @. $(DOCS_VENV); test -d $(DOCS_VENVDIR)/lib/python*/site-packages/vale || pip install vale - @. $(DOCS_VENV); test -f $(SPHINX_DIR)/vale.ini || python3 $(SPHINX_DIR)/get_vale_conf.py - @. $(DOCS_VENV); find $(DOCS_VENVDIR)/lib/python*/site-packages/vale/vale_bin -size 195c -exec vale --config "$(SPHINX_DIR)/vale.ini" $(TARGET) > /dev/null \; - @echo "" - @echo "Running Vale against $(TARGET). To change target set TARGET= with make command" - @echo "" - @. $(DOCS_VENV); vale --config "$(SPHINX_DIR)/vale.ini" --glob='*.{md,txt,rst}' $(TARGET) -# `spelling` checks only the MicroCloud docs. -spelling: clean-doc microcloud spellcheck - -spellcheck: install - . $(DOCS_VENV); python3 -m pyspelling -c $(SPHINX_DIR)/spellingcheck.yaml -j $(shell nproc) - +vale-install: install + @. $(DOCS_VENV); test -f $(VALE_CONFIG) || python3 $(SPHINX_DIR)/get_vale_conf.py + @echo '.Name=="Canonical.400-Enforce-inclusive-terms"' > $(SPHINX_DIR)/styles/woke.filter + @echo '.Level=="error" and .Name!="Canonical.500-Repeated-words" and .Name!="Canonical.000-US-spellcheck"' > $(SPHINX_DIR)/styles/error.filter + @echo '.Name=="Canonical.000-US-spellcheck"' > $(SPHINX_DIR)/styles/spelling.filter + @. $(DOCS_VENV); find $(VALE_DIR)/vale_bin -size 195c -exec vale --version \; + +woke: vale-install + @cat $(DOCS_VOCAB)/accept.txt > $(DOCS_VOCAB)/accept_backup.txt + @cat $(DOCS_SOURCEDIR)/.custom_wordlist.txt >> $(DOCS_VOCAB)/accept.txt + @echo "Running Vale acceptable term check against $(CHECK_PATH). To change target set CHECK_PATH= with make command" + @. $(DOCS_VENV); vale --config="$(VALE_CONFIG)" --filter='$(SPHINX_DIR)/styles/woke.filter' --glob='*.{md,rst}' $(CHECK_PATH) + @cat $(DOCS_VOCAB)/accept_backup.txt > $(DOCS_VOCAB)/accept.txt && rm $(DOCS_VOCAB)/accept_backup.txt + +vale: vale-install + @cat $(DOCS_VOCAB)/accept.txt > $(DOCS_VOCAB)/accept_backup.txt + @cat $(DOCS_SOURCEDIR)/.custom_wordlist.txt >> $(DOCS_VOCAB)/accept.txt + @echo "Running Vale against $(CHECK_PATH). To change target set CHECK_PATH= with make command" + @. $(DOCS_VENV); vale --config="$(VALE_CONFIG)" --filter='$(SPHINX_DIR)/styles/error.filter' --glob='*.{md,rst}' $(CHECK_PATH) + @cat $(DOCS_VOCAB)/accept_backup.txt > $(DOCS_VOCAB)/accept.txt && rm $(DOCS_VOCAB)/accept_backup.txt + +spelling: vale-install + @cat $(DOCS_VOCAB)/accept.txt > $(DOCS_VOCAB)/accept_backup.txt + @cat $(DOCS_SOURCEDIR)/.custom_wordlist.txt >> $(DOCS_VOCAB)/accept.txt + @echo "Running Vale against $(CHECK_PATH). To change target set CHECK_PATH= with make command" + @. $(DOCS_VENV); vale --config="$(VALE_CONFIG)" --filter='$(SPHINX_DIR)/styles/spelling.filter' --glob='*.{md,rst}' $(CHECK_PATH) + @cat $(DOCS_VOCAB)/accept_backup.txt > $(DOCS_VOCAB)/accept.txt && rm $(DOCS_VOCAB)/accept_backup.txt + +spellcheck: spelling + @echo "Please note that the \`make spellcheck\` command is being deprecated in favor of \`make spelling\`" # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINX_OPTS). diff --git a/doc/conf.py b/doc/conf.py index ba6d6c6d6..a8d73a9b0 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -218,6 +218,12 @@ rst_prolog = ''' .. role:: center :class: align-center +.. role:: h2 + :class: hclass2 +.. role:: woke-ignore + :class: woke-ignore +.. role:: vale-ignore + :class: vale-ignore ''' # Load substitutions from YAML file diff --git a/doc/requirements.txt b/doc/requirements.txt index c82507181..c6be53bd5 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -21,7 +21,6 @@ sphinx-youtube-links~=0.1 # Other dependencies packaging~=26.1 -pyspelling sphinxcontrib-svg2pdfconverter[CairoSVG]~=2.1 sphinx-last-updated-by-git~=0.3 sphinx-sitemap~=2.9 From 2c1da1f54aad6097254cc91323f8b2a918b7cd2b Mon Sep 17 00:00:00 2001 From: Minae Lee Date: Mon, 4 May 2026 15:56:43 -0700 Subject: [PATCH 12/26] doc: fix vale-flagged spelling/woke issues Signed-off-by: Minae Lee (cherry picked from commit 5bbacb5a0c5f336f3fe9907425205e2034fbc46b) Amended: removed "SSL" from `.custom_wordlist.txt` (specific to MicroCloud 3 documentation) and did not add the release notes template. Signed-off-by: Elijah Greenstein --- doc/.custom_wordlist.txt | 1 + doc/explanation/security.md | 2 +- doc/how-to/member_remove.md | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/.custom_wordlist.txt b/doc/.custom_wordlist.txt index 7067c6bfc..27910882a 100644 --- a/doc/.custom_wordlist.txt +++ b/doc/.custom_wordlist.txt @@ -69,6 +69,7 @@ scalable SDN snapd SSD +subfolders subnet subnets SVG diff --git a/doc/explanation/security.md b/doc/explanation/security.md index 64a638ff1..8ab18e742 100644 --- a/doc/explanation/security.md +++ b/doc/explanation/security.md @@ -31,7 +31,7 @@ Report potential security issues privately through GitHub by [filing a security MicroCloud manages cluster membership and encrypted communication through mTLS and certificate-based identities. When a machine joins a cluster, it verifies the cluster’s certificate fingerprint and receives the complete set of member certificates, establishing a consistent trust store. -During the join process, MicroCloud uses an **explicit trust establishment mechanism** designed to prevent secret leakage and mitigate man-in-the-middle attacks. This mechanism uses a Hash-Based Message Authentication Code (HMAC) to sign the messages exchanged between the machine that initiates the join process and the joining peers. The shared secret used for joining is never transmitted over the network. The join process also enforces rate limits and session timeouts to reduce the risk of replay and brute-force attacks. For further information, refer to the [public specification](https://discourse.ubuntu.com/t/explicit-trust-establishment-mechanism-for-microcloud/44261). +During the join process, MicroCloud uses an **explicit trust establishment mechanism** designed to prevent secret leakage and mitigate {spellexception}`man-in-the-middle` attacks. This mechanism uses a Hash-Based Message Authentication Code (HMAC) to sign the messages exchanged between the machine that initiates the join process and the joining peers. The shared secret used for joining is never transmitted over the network. The join process also enforces rate limits and session timeouts to reduce the risk of replay and brute-force attacks. For further information, refer to the [public specification](https://discourse.ubuntu.com/t/explicit-trust-establishment-mechanism-for-microcloud/44261). (exp-security-lxd)= ## LXD diff --git a/doc/how-to/member_remove.md b/doc/how-to/member_remove.md index 52e6dee5b..72128ea4f 100644 --- a/doc/how-to/member_remove.md +++ b/doc/how-to/member_remove.md @@ -33,7 +33,7 @@ Removing a cluster member with `--force` will not attempt to perform any clean-u ## Reducing the cluster to one member -When shrinking the cluster down to one member, you must also clean up the Ceph monmap before proceeding, even when using the `--force` flag. +When shrinking the cluster down to one member, you must also clean up the Ceph monitor map (`monmap`) before proceeding, even when using the `--force` flag. ```bash sudo microceph.ceph mon remove From b372eabbb2bcd233b956a9cd5afb798659d7c009 Mon Sep 17 00:00:00 2001 From: Minae Lee Date: Mon, 4 May 2026 19:08:43 -0700 Subject: [PATCH 13/26] doc: use canonical-sphinx theme with customizations Replaces use of the canonical-sphinx-extensions extension with the canonical-sphinx extension, adapted for MicroCloud customizations. The canonical-sphinx-extensions package included multiple extensions that have now been split out into their own extensions and updated, including sphinx-terminal, and these have been re-added as needed. Signed-off-by: Minae Lee (cherry picked from commit 4827710e0ce6b23101b033eb35ab7825d5ac6b8b) --- doc/.sphinx/_static/404.svg | 13 - doc/.sphinx/_static/custom.css | 378 ------------------ doc/.sphinx/_static/footer.css | 47 --- doc/.sphinx/_static/footer.js | 12 - doc/.sphinx/_static/furo_colors.css | 89 ----- doc/.sphinx/_static/github_issue_links.css | 24 -- doc/.sphinx/_static/github_issue_links.js | 34 -- doc/.sphinx/_static/header-nav.js | 10 - doc/.sphinx/_static/header.css | 167 -------- .../_static/{tag.png => microcloud_tag.png} | Bin doc/.sphinx/_templates/404.html | 17 - doc/.sphinx/_templates/footer.html | 76 +--- doc/.sphinx/_templates/header.html | 42 +- doc/.sphinx/_templates/page.html | 49 --- doc/Makefile | 4 +- doc/conf.py | 54 +-- doc/requirements.txt | 4 +- 17 files changed, 72 insertions(+), 948 deletions(-) delete mode 100644 doc/.sphinx/_static/404.svg delete mode 100644 doc/.sphinx/_static/custom.css delete mode 100644 doc/.sphinx/_static/footer.css delete mode 100644 doc/.sphinx/_static/footer.js delete mode 100644 doc/.sphinx/_static/furo_colors.css delete mode 100644 doc/.sphinx/_static/github_issue_links.css delete mode 100644 doc/.sphinx/_static/github_issue_links.js delete mode 100644 doc/.sphinx/_static/header-nav.js delete mode 100644 doc/.sphinx/_static/header.css rename doc/.sphinx/_static/{tag.png => microcloud_tag.png} (100%) delete mode 100644 doc/.sphinx/_templates/404.html delete mode 100644 doc/.sphinx/_templates/page.html diff --git a/doc/.sphinx/_static/404.svg b/doc/.sphinx/_static/404.svg deleted file mode 100644 index b353cd339..000000000 --- a/doc/.sphinx/_static/404.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - diff --git a/doc/.sphinx/_static/custom.css b/doc/.sphinx/_static/custom.css deleted file mode 100644 index 3ceeb188e..000000000 --- a/doc/.sphinx/_static/custom.css +++ /dev/null @@ -1,378 +0,0 @@ -/** - Ubuntu variable font definitions. - Based on https://github.com/canonical/vanilla-framework/blob/main/scss/_base_fontfaces.scss - - When font files are updated in Vanilla, the links to font files will need to be updated here as well. -*/ - -/* default font set */ -@font-face { - font-family: 'Ubuntu variable'; - font-stretch: 100%; /* min and max value for the width axis, expressed as percentage */ - font-style: normal; - font-weight: 100 800; /* min and max value for the weight axis */ - src: url('https://assets.ubuntu.com/v1/f1ea362b-Ubuntu%5Bwdth,wght%5D-latin-v0.896a.woff2') format('woff2-variations'); -} - -@font-face { - font-family: 'Ubuntu variable'; - font-stretch: 100%; /* min and max value for the width axis, expressed as percentage */ - font-style: italic; - font-weight: 100 800; /* min and max value for the weight axis */ - src: url('https://assets.ubuntu.com/v1/90b59210-Ubuntu-Italic%5Bwdth,wght%5D-latin-v0.896a.woff2') format('woff2-variations'); -} - -@font-face { - font-family: 'Ubuntu Mono variable'; - font-style: normal; - font-weight: 100 800; /* min and max value for the weight axis */ - src: url('https://assets.ubuntu.com/v1/d5fc1819-UbuntuMono%5Bwght%5D-latin-v0.869.woff2') format('woff2-variations'); -} - -/* cyrillic-ext */ -@font-face { - font-family: 'Ubuntu variable'; - font-stretch: 100%; /* min and max value for the width axis, expressed as percentage */ - font-style: normal; - font-weight: 100 800; /* min and max value for the weight axis */ - src: url('https://assets.ubuntu.com/v1/77cd6650-Ubuntu%5Bwdth,wght%5D-cyrillic-extended-v0.896a.woff2') format('woff2-variations'); - unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F; -} - -/* cyrillic */ -@font-face { - font-family: 'Ubuntu variable'; - font-stretch: 100%; /* min and max value for the width axis, expressed as percentage */ - font-style: normal; - font-weight: 100 800; /* min and max value for the weight axis */ - src: url('https://assets.ubuntu.com/v1/2702fce5-Ubuntu%5Bwdth,wght%5D-cyrillic-v0.896a.woff2') format('woff2-variations'); - unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; -} - -/* greek-ext */ -@font-face { - font-family: 'Ubuntu variable'; - font-stretch: 100%; /* min and max value for the width axis, expressed as percentage */ - font-style: normal; - font-weight: 100 800; /* min and max value for the weight axis */ - src: url('https://assets.ubuntu.com/v1/5c108b7d-Ubuntu%5Bwdth,wght%5D-greek-extended-v0.896a.woff2') format('woff2-variations'); - unicode-range: U+1F00-1FFF; -} - -/* greek */ -@font-face { - font-family: 'Ubuntu variable'; - font-stretch: 100%; /* min and max value for the width axis, expressed as percentage */ - font-style: normal; - font-weight: 100 800; /* min and max value for the weight axis */ - src: url('https://assets.ubuntu.com/v1/0a14c405-Ubuntu%5Bwdth,wght%5D-greek-v0.896a.woff2') format('woff2-variations'); - unicode-range: U+0370-03FF; -} - -/* latin-ext */ -@font-face { - font-family: 'Ubuntu variable'; - font-stretch: 100%; /* min and max value for the width axis, expressed as percentage */ - font-style: normal; - font-weight: 100 800; /* min and max value for the weight axis */ - src: url('https://assets.ubuntu.com/v1/19f68eeb-Ubuntu%5Bwdth,wght%5D-latin-extended-v0.896a.woff2') format('woff2-variations'); - unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF; -} - - -/** Define font-weights as per Vanilla - Based on: https://github.com/canonical/vanilla-framework/blob/main/scss/_base_typography-definitions.scss - - regular text: 400, - bold: 550, - thin: 300, - - h1: bold, - h2: 180; - h3: bold, - h4: 275, - h5: bold, - h6: regular -*/ - -/* default regular text */ -html { - font-weight: 400; -} - -/* heading specific definitions */ -h1, h3, h5 { font-weight: 550; } -h2 { font-weight: 180; } -h4 { font-weight: 275; } - -/* bold */ -.toc-tree li.scroll-current>.reference, -dl.glossary dt, -dl.simple dt, -dl:not([class]) dt { - font-weight: 550; -} - - -/** Table styling **/ - -th.head { - text-transform: uppercase; - font-size: var(--font-size--small); - text-align: initial; -} - -table.align-center th.head { - text-align: center -} - -table.docutils { - border: 0; - box-shadow: none; - width:100%; -} - -table.docutils td, table.docutils th, table.docutils td:last-child, table.docutils th:last-child, table.docutils td:first-child, table.docutils th:first-child { - border-right: none; - border-left: none; -} - -/* Allow to centre text horizontally in table data cells */ -table.align-center { - text-align: center !important; -} - -/** No rounded corners **/ - -.admonition, code.literal, .sphinx-tabs-tab, .sphinx-tabs-panel, .highlight { - border-radius: 0; -} - -/** Admonition styling **/ - -.admonition { - border-top: 1px solid #d9d9d9; - border-right: 1px solid #d9d9d9; - border-bottom: 1px solid #d9d9d9; -} - -/** Color for the "copy link" symbol next to headings **/ - -a.headerlink { - color: var(--color-brand-primary); -} - -/** Line to the left of the current navigation entry **/ - -.sidebar-tree li.current-page { - border-left: 2px solid var(--color-brand-primary); -} - -/** Some tweaks for Sphinx tabs **/ - -[role="tablist"] { - border-bottom: 1px solid var(--color-sidebar-item-background--hover); -} - -.sphinx-tabs-tab[aria-selected="true"], .sd-tab-set>input:checked+label{ - border: 0; - border-bottom: 2px solid var(--color-brand-primary); - font-weight: 400; - font-size: 1rem; - color: var(--color-brand-primary); -} - -body[data-theme="dark"] .sphinx-tabs-tab[aria-selected="true"] { - background: var(--color-background-primary); - border-bottom: 2px solid var(--color-brand-primary); -} - -button.sphinx-tabs-tab[aria-selected="false"]:hover, .sd-tab-set>input:not(:checked)+label:hover { - border-bottom: 2px solid var(--color-foreground-border); -} - -button.sphinx-tabs-tab[aria-selected="false"]{ - border-bottom: 2px solid var(--color-background-primary); -} - -body[data-theme="dark"] .sphinx-tabs-tab { - background: var(--color-background-primary); -} - -.sphinx-tabs-tab, .sd-tab-set>label{ - color: var(--color-brand-primary); - font-family: var(--font-stack); - font-weight: 400; - font-size: 1rem; - padding: 1em 1.25em .5em -} - -.sphinx-tabs-panel { - border: 0; - border-bottom: 1px solid var(--color-sidebar-item-background--hover); - background: var(--color-background-primary); - padding: 0.75rem 0 0.75rem 0; -} - -body[data-theme="dark"] .sphinx-tabs-panel { - background: var(--color-background-primary); -} - -/** A tweak for issue #190 **/ - -.highlight .hll { - background-color: var(--color-highlighted-background); -} - - -/** Custom classes to fix scrolling in tables by decreasing the - font size or breaking certain columns. - Specify the classes in the Markdown file with, for example: - ```{rst-class} break-col-4 min-width-4-8 - ``` -**/ - -table.dec-font-size { - font-size: smaller; -} -table.break-col-1 td.text-left:first-child { - word-break: break-word; -} -table.break-col-4 td.text-left:nth-child(4) { - word-break: break-word; -} -table.min-width-1-15 td.text-left:first-child { - min-width: 15em; -} -table.min-width-4-8 td.text-left:nth-child(4) { - min-width: 8em; -} - -/** Underline for abbreviations **/ - -abbr[title] { - text-decoration: underline solid #cdcdcd; -} - -/** Use the same style for right-details as for left-details **/ -.bottom-of-page .right-details { - font-size: var(--font-size--small); - display: block; -} - -/** Version switcher */ -button.version_select { - color: var(--color-foreground-primary); - background-color: var(--color-toc-background); - padding: 5px 10px; - border: none; -} - -.version_select:hover, .version_select:focus { - background-color: var(--color-sidebar-item-background--hover); -} - -.version_dropdown { - position: relative; - display: inline-block; - text-align: right; - font-size: var(--sidebar-item-font-size); -} - -.available_versions { - display: none; - position: absolute; - right: 0px; - background-color: var(--color-toc-background); - box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); - z-index: 11; -} - -.available_versions a { - color: var(--color-foreground-primary); - padding: 12px 16px; - text-decoration: none; - display: block; -} - -.available_versions a:hover {background-color: var(--color-sidebar-item-background--current)} - -/** Suppress link underlines outside on-hover **/ -a { - text-decoration: none; -} - -a:hover, a:visited:hover { - text-decoration: underline; -} - -.show {display:block;} - -/** Fix for nested numbered list - the nested list is lettered **/ -ol.arabic ol.arabic { - list-style: lower-alpha; -} - -/** Make expandable sections look like links **/ -details summary { - color: var(--color-link); -} - -/** Fix the styling of the version box for readthedocs **/ - -#furo-readthedocs-versions .rst-versions, #furo-readthedocs-versions .rst-current-version, #furo-readthedocs-versions:focus-within .rst-current-version, #furo-readthedocs-versions:hover .rst-current-version { - background: var(--color-sidebar-item-background--hover); -} - -.rst-versions .rst-other-versions dd a { - color: var(--color-link); -} - -#furo-readthedocs-versions:focus-within .rst-current-version .fa-book, #furo-readthedocs-versions:hover .rst-current-version .fa-book, .rst-versions .rst-other-versions { - color: var(--color-sidebar-link-text); -} - -.rst-versions .rst-current-version { - color: var(--color-version-popup); - font-weight: bolder; -} - -/* Code-block copybutton invisible by default - (overriding Furo config to achieve default copybutton setting). */ -.highlight button.copybtn { - opacity: 0; -} - -/* Mimicking the 'Give feedback' button for UX consistency */ -.sidebar-search-container input[type=submit] { - color: #FFFFFF; - border: 2px solid #D6410D; - padding: var(--sidebar-search-input-spacing-vertical) var(--sidebar-search-input-spacing-horizontal); - background: #D6410D; - font-weight: bold; - font-size: var(--font-size--small); - cursor: pointer; -} - -.sidebar-search-container input[type=submit]:hover { - text-decoration: underline; -} - -/* Make inline code the same size as code blocks */ -p code.literal { - border: 0; - font-size: var(--code-font-size); -} - -/* Use the general admonition font size for inline code */ -.admonition p code.literal { - font-size: var(--admonition-font-size); -} - -.highlight .s, .highlight .s1, .highlight .s2 { - color: #3F8100; -} - -.highlight .o { - color: #BB5400; -} diff --git a/doc/.sphinx/_static/footer.css b/doc/.sphinx/_static/footer.css deleted file mode 100644 index a0a1db454..000000000 --- a/doc/.sphinx/_static/footer.css +++ /dev/null @@ -1,47 +0,0 @@ -.display-contributors { - color: var(--color-sidebar-link-text); - cursor: pointer; -} -.all-contributors { - display: none; - z-index: 55; - list-style: none; - position: fixed; - top: 0; - bottom: 0; - left: 0; - right: 0; - width: 200px; - height: 200px; - overflow-y: scroll; - margin: auto; - padding: 0; - background: var(--color-background-primary); - scrollbar-color: var(--color-foreground-border) transparent; - scrollbar-width: thin; -} - -.all-contributors li:hover { - background: var(--color-sidebar-item-background--hover); - width: 100%; -} - -.all-contributors li a{ - color: var(--color-sidebar-link-text); - padding: 1rem; - display: inline-block; -} - -#overlay { - position: fixed; - display: none; - width: 100%; - height: 100%; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(0,0,0,0.5); - z-index: 2; - cursor: pointer; -} diff --git a/doc/.sphinx/_static/footer.js b/doc/.sphinx/_static/footer.js deleted file mode 100644 index 9a08b1e99..000000000 --- a/doc/.sphinx/_static/footer.js +++ /dev/null @@ -1,12 +0,0 @@ -$(document).ready(function() { - $(document).on("click", function () { - $(".all-contributors").hide(); - $("#overlay").hide(); - }); - - $('.display-contributors').click(function(event) { - $('.all-contributors').toggle(); - $("#overlay").toggle(); - event.stopPropagation(); - }); -}) diff --git a/doc/.sphinx/_static/furo_colors.css b/doc/.sphinx/_static/furo_colors.css deleted file mode 100644 index 4cfdbe7bf..000000000 --- a/doc/.sphinx/_static/furo_colors.css +++ /dev/null @@ -1,89 +0,0 @@ -body { - --color-code-background: #f8f8f8; - --color-code-foreground: black; - --code-font-size: 1rem; - --font-stack: Ubuntu variable, Ubuntu, -apple-system, Segoe UI, Roboto, Oxygen, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; - --font-stack--monospace: Ubuntu Mono variable, Ubuntu Mono, Consolas, Monaco, Courier, monospace; - --color-foreground-primary: #111; - --color-foreground-secondary: var(--color-foreground-primary); - --color-foreground-muted: #333; - --color-background-secondary: #FFF; - --color-background-hover: #f2f2f2; - --color-brand-primary: #111; - --color-brand-content: #06C; - --color-api-background: #E3E3E3; - --color-inline-code-background: rgba(0,0,0,.03); - --color-sidebar-link-text: #111; - --color-sidebar-item-background--current: #ebebeb; - --color-sidebar-item-background--hover: #f2f2f2; - --toc-font-size: var(--font-size--small); - --color-admonition-title-background--note: var(--color-background-primary); - --color-admonition-title-background--tip: var(--color-background-primary); - --color-admonition-title-background--important: var(--color-background-primary); - --color-admonition-title-background--caution: var(--color-background-primary); - --color-admonition-title--note: #24598F; - --color-admonition-title--tip: #24598F; - --color-admonition-title--important: #C7162B; - --color-admonition-title--caution: #F99B11; - --color-highlighted-background: #EBEBEB; - --color-link-underline: var(--color-link); - --color-link-underline--hover: var(--color-link); - --color-link-underline--visited: var(--color-link--visited); - --color-link-underline--visited--hover: var(--color-link--visited); - --color-version-popup: #772953; -} - -@media not print { - body[data-theme="dark"] { - --color-code-background: #202020; - --color-code-foreground: #d0d0d0; - --color-foreground-secondary: var(--color-foreground-primary); - --color-foreground-muted: #CDCDCD; - --color-background-secondary: var(--color-background-primary); - --color-background-hover: #666; - --color-brand-primary: #fff; - --color-brand-content: #69C; - --color-sidebar-link-text: #f7f7f7; - --color-sidebar-item-background--current: #666; - --color-sidebar-item-background--hover: #333; - --color-admonition-background: transparent; - --color-admonition-title-background--note: var(--color-background-primary); - --color-admonition-title-background--tip: var(--color-background-primary); - --color-admonition-title-background--important: var(--color-background-primary); - --color-admonition-title-background--caution: var(--color-background-primary); - --color-admonition-title--note: #24598F; - --color-admonition-title--tip: #24598F; - --color-admonition-title--important: #C7162B; - --color-admonition-title--caution: #F99B11; - --color-highlighted-background: #666; - --color-version-popup: #F29879; - } - @media (prefers-color-scheme: dark) { - body:not([data-theme="light"]) { - --color-api-background: #A4A4A4; - --color-code-background: #202020; - --color-code-foreground: #d0d0d0; - --color-foreground-secondary: var(--color-foreground-primary); - --color-foreground-muted: #CDCDCD; - --color-background-secondary: var(--color-background-primary); - --color-background-hover: #666; - --color-brand-primary: #fff; - --color-brand-content: #69C; - --color-sidebar-link-text: #f7f7f7; - --color-sidebar-item-background--current: #666; - --color-sidebar-item-background--hover: #333; - --color-admonition-background: transparent; - --color-admonition-title-background--note: var(--color-background-primary); - --color-admonition-title-background--tip: var(--color-background-primary); - --color-admonition-title-background--important: var(--color-background-primary); - --color-admonition-title-background--caution: var(--color-background-primary); - --color-admonition-title--note: #24598F; - --color-admonition-title--tip: #24598F; - --color-admonition-title--important: #C7162B; - --color-admonition-title--caution: #F99B11; - --color-highlighted-background: #666; - --color-link: #F9FCFF; - --color-version-popup: #F29879; - } - } -} diff --git a/doc/.sphinx/_static/github_issue_links.css b/doc/.sphinx/_static/github_issue_links.css deleted file mode 100644 index db166ed95..000000000 --- a/doc/.sphinx/_static/github_issue_links.css +++ /dev/null @@ -1,24 +0,0 @@ -.github-issue-link-container { - padding-right: 0.5rem; -} -.github-issue-link { - font-size: var(--font-size--small); - font-weight: bold; - background-color: #D6410D; - padding: 13px 23px; - text-decoration: none; -} -.github-issue-link:link { - color: #FFFFFF; -} -.github-issue-link:visited { - color: #FFFFFF -} -.muted-link.github-issue-link:hover { - color: #FFFFFF; - text-decoration: underline; -} -.github-issue-link:active { - color: #FFFFFF; - text-decoration: underline; -} diff --git a/doc/.sphinx/_static/github_issue_links.js b/doc/.sphinx/_static/github_issue_links.js deleted file mode 100644 index f0706038b..000000000 --- a/doc/.sphinx/_static/github_issue_links.js +++ /dev/null @@ -1,34 +0,0 @@ -// if we already have an onload function, save that one -var prev_handler = window.onload; - -window.onload = function() { - // call the previous onload function - if (prev_handler) { - prev_handler(); - } - - const link = document.createElement("a"); - link.classList.add("muted-link"); - link.classList.add("github-issue-link"); - link.text = "Give feedback"; - link.href = ( - github_url - + "/issues/new?" - + "title=docs%3A+TYPE+YOUR+QUESTION+HERE" - + "&body=*Please describe the question or issue you're facing with " - + `"${document.title}"` - + ".*" - + "%0A%0A%0A%0A%0A" - + "---" - + "%0A" - + `*Reported+from%3A+${location.href}*` - ); - link.target = "_blank"; - - const div = document.createElement("div"); - div.classList.add("github-issue-link-container"); - div.append(link) - - const container = document.querySelector(".article-container > .content-icon-container"); - container.prepend(div); -}; diff --git a/doc/.sphinx/_static/header-nav.js b/doc/.sphinx/_static/header-nav.js deleted file mode 100644 index 3608576e0..000000000 --- a/doc/.sphinx/_static/header-nav.js +++ /dev/null @@ -1,10 +0,0 @@ -$(document).ready(function() { - $(document).on("click", function () { - $(".more-links-dropdown").hide(); - }); - - $('.nav-more-links').click(function(event) { - $('.more-links-dropdown').toggle(); - event.stopPropagation(); - }); -}) diff --git a/doc/.sphinx/_static/header.css b/doc/.sphinx/_static/header.css deleted file mode 100644 index 0b9440903..000000000 --- a/doc/.sphinx/_static/header.css +++ /dev/null @@ -1,167 +0,0 @@ -.p-navigation { - border-bottom: 1px solid var(--color-sidebar-background-border); -} - -.p-navigation__nav { - background: #333333; - display: flex; -} - -.p-logo { - display: flex !important; - padding-top: 0 !important; - text-decoration: none; -} - -.p-logo-image { - height: 44px; - padding-right: 10px; -} - -.p-logo-text { - margin-top: 18px; - color: white; - text-decoration: none; -} - -ul.p-navigation__links { - display: flex; - list-style: none; - margin-left: 0; - margin-top: auto; - margin-bottom: auto; - max-width: 800px; - width: 100%; -} - -ul.p-navigation__links li { - margin: 0 auto; - text-align: center; - width: 100%; -} - -ul.p-navigation__links li a { - background-color: rgba(0, 0, 0, 0); - border: none; - border-radius: 0; - color: var(--color-sidebar-link-text); - display: block; - font-weight: 400; - line-height: 1.5rem; - margin: 0; - overflow: hidden; - padding: 1rem 0; - position: relative; - text-align: left; - text-overflow: ellipsis; - transition-duration: .1s; - transition-property: background-color, color, opacity; - transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); - white-space: nowrap; - width: 100%; -} - -ul.p-navigation__links .p-navigation__link { - color: #ffffff; - font-weight: 300; - text-align: center; - text-decoration: none; -} - -ul.p-navigation__links .p-navigation__link:hover { - background-color: #2b2b2b; -} - -ul.p-navigation__links .p-dropdown__link:hover { - background-color: var(--color-sidebar-item-background--hover); -} - -ul.p-navigation__links .p-navigation__sub-link { - background: var(--color-background-primary); - padding: .5rem 0 .5rem .5rem; - font-weight: 300; -} - -ul.p-navigation__links .more-links-dropdown li a { - border-left: 1px solid var(--color-sidebar-background-border); - border-right: 1px solid var(--color-sidebar-background-border); -} - -ul.p-navigation__links .more-links-dropdown li:first-child a { - border-top: 1px solid var(--color-sidebar-background-border); -} - -ul.p-navigation__links .more-links-dropdown li:last-child a { - border-bottom: 1px solid var(--color-sidebar-background-border); -} - -ul.p-navigation__links .p-navigation__logo { - padding: 0.5rem; -} - -ul.p-navigation__links .p-navigation__logo img { - width: 40px; -} - -ul.more-links-dropdown { - display: none; - overflow-x: visible; - height: 0; - z-index: 55; - padding: 0; - position: relative; - list-style: none; - margin-bottom: 0; - margin-top: 0; -} - -.nav-more-links::after { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3E%3Cpath fill='%23111' d='M8.187 11.748l6.187-6.187-1.06-1.061-5.127 5.127L3.061 4.5 2 5.561z'/%3E%3C/svg%3E"); - background-position: center; - background-repeat: no-repeat; - background-size: contain; - content: ""; - display: block; - filter: invert(100%); - height: 1rem; - pointer-events: none; - position: absolute; - right: 1rem; - text-indent: calc(100% + 10rem); - top: calc(1rem + 0.25rem); - width: 1rem; -} - -.nav-ubuntu-com { - display: none; -} - -@media only screen and (min-width: 480px) { - ul.p-navigation__links li { - width: 100%; - } - - .nav-ubuntu-com { - display: inherit; - } -} - -@media only screen and (max-width: 800px) { - .nav-more-links { - margin-left: auto !important; - padding-right: 2rem !important; - width: 8rem !important; - } -} - -@media only screen and (min-width: 800px) { - ul.p-navigation__links li { - width: 100% !important; - } -} - -@media only screen and (min-width: 1310px) { - ul.p-navigation__links { - margin-left: calc(50% - 41em); - } -} diff --git a/doc/.sphinx/_static/tag.png b/doc/.sphinx/_static/microcloud_tag.png similarity index 100% rename from doc/.sphinx/_static/tag.png rename to doc/.sphinx/_static/microcloud_tag.png diff --git a/doc/.sphinx/_templates/404.html b/doc/.sphinx/_templates/404.html deleted file mode 100644 index 4cb2d50d3..000000000 --- a/doc/.sphinx/_templates/404.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends "page.html" %} - -{% block content -%} -
-

Page not found

-
-
-
- {{ body }} -
-
- Penguin with a question mark -
-
-
-
-{%- endblock content %} diff --git a/doc/.sphinx/_templates/footer.html b/doc/.sphinx/_templates/footer.html index 577478c95..242f91ab3 100644 --- a/doc/.sphinx/_templates/footer.html +++ b/doc/.sphinx/_templates/footer.html @@ -5,7 +5,7 @@ {% if meta %} {% if 'sequential_nav' in meta %} {% set sequential_nav = meta.sequential_nav %} - {% endif %} + {% endif %} {% endif %} {# mod: Conditional wrappers to control page navigation buttons #} {% if sequential_nav != "none" -%} @@ -43,15 +43,26 @@ {%- endif %} + {%- if license and license.name -%} + {%- if license.url -%} +
+ This page is licensed under {{ license.name }} +
+ {%- else -%} +
+ This page is licensed under {{ license.name }} +
+ {%- endif -%} + {%- endif -%} {# mod: removed "Made with" #} @@ -70,65 +81,8 @@ {%- endif %} -
- {% if github_url and github_folder and pagename and page_source_suffix and display_contributors %} - {% set contributors = get_contribs(github_url, github_folder, pagename, page_source_suffix, display_contributors_since) %} - {% if contributors %} - {% if contributors | length > 1 %} - Thanks to the {{ contributors |length }} contributors! - {% else %} - Thanks to our contributor! - {% endif %} -
- - {% endif %} - {% endif %} -
- - {# mod: replaced RTD icons with our links #} - - {% if discourse %} - - {% endif %} - - {% if mattermost %} - - {% endif %} - - {% if matrix %} - - {% endif %} - - {% if github_url and github_version and github_folder %} - - {% if github_issues %} - - {% endif %} - - - {% endif %} - {# mod: Added link to manage cookie tracker settings #} - - -
+ diff --git a/doc/.sphinx/_templates/header.html b/doc/.sphinx/_templates/header.html index bf2cb23e8..60508aa21 100644 --- a/doc/.sphinx/_templates/header.html +++ b/doc/.sphinx/_templates/header.html @@ -7,28 +7,58 @@