Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ This file contains short, concrete guidance for AI coding agents working in this

## Quick context
- Project: documentation built with Sphinx (MyST/Markdown + some reST).
- Key directories: `docs/` (content), `docs/.sphinx/` (style/config helpers), `.github/workflows/` (CI).
- Primary build: virtualenv at `docs/.sphinx/venv` created by `make install` from the repo root.
- Key directories: `docs/` (content), `docs/_dev/` (style/config helpers), `.github/workflows/` (CI).
- Primary build: virtualenv at `docs/.venv` created by `make install` from the repo root.

## Most useful commands (examples)
- Create venv & install deps: `make install` (from repo root).
Expand All @@ -33,14 +33,14 @@ This file contains short, concrete guidance for AI coding agents working in this
## Files to check/read when changing behavior or styling
- `docs/conf.py` — Sphinx configuration and extensions (canonical_sphinx, myst, intersphinx).
- `docs/Makefile` — canonical make targets and environment expectations (venv location, PIPOPTS usage).
- `docs/.sphinx/.markdownlint.json` and `docs/.sphinx/spellingcheck.yaml` — editorial/style rules used by CI.
- `docs/.sphinx/pa11y.json` and `docs/.sphinx/.wordlist.txt` — accessibility and spelling exceptions.
- `docs/_dev/.pymarkdown.json` — Markdown lint configuration.
- `docs/_dev/pa11y.json` — accessibility checker configuration.
- `.github/workflows/*` — CI entrypoints and special flags (e.g. docs-only triggers).

## How to propose edits (recommended checklist)
1. Run `make run` locally and visually confirm layout and link changes.
2. Run `make linkcheck` and `make vale` to catch link/style issues early.
3. Check `docs/.sphinx/*` for project-specific lint/spell rules and adhere to them.
3. Check `docs/_dev/*` for project-specific lint/spell rules and adhere to them.
4. Push a branch and open a PR; CI will validate markdown style and Sphinx build on `docs/**` changes.

## Examples from this repo (quick references)
Expand Down
2 changes: 1 addition & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ build:
sphinx:
builder: dirhtml
configuration: docs/conf.py
fail_on_warning: false
fail_on_warning: true

# If using Sphinx, optionally build your docs in additional formats such as PDF
formats:
Expand Down
7 changes: 3 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ To install the prerequisites:

make install

This will create a virtual environment (``.sphinx/venv``) and install
dependency software (``.sphinx/requirements.txt``) within it.
This will create a virtual environment (``.venv``) and install dependency
software from ``requirements.txt`` within it.

View the documentation
~~~~~~~~~~~~~~~~~~~~~~
Expand All @@ -43,5 +43,4 @@ The ``run`` target is therefore very convenient when preparing to submit a
change to the documentation.

.. LINKS
.. _`Documentation starter pack`: https://github.com/canonical/sphinx-docs-starter-pack/tree/main

.. _`Sphinx Stack`: https://github.com/canonical/sphinx-stack
2 changes: 1 addition & 1 deletion UPDATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,4 @@ allowed outside the GitHub repository, according to the following workflow:
[RTD Webpage](https://app.readthedocs.com/projects/canonical-snap/).
The build takes approximately 20 minutes.
3. If the build process is successful, the generated documentation will be
hosted [here](https://canonical-snap.readthedocs-hosted.com/).
hosted [here](https://canonical-snap.readthedocs-hosted.com/).
16 changes: 8 additions & 8 deletions docs/.gitignore
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# Environment
*env*/
.sphinx/venv/
.venv/

# Sphinx
.sphinx/warnings.txt
.sphinx/.wordlist.dic
.sphinx/.doctrees/
.sphinx/update/
.sphinx/node_modules/
_dev/warnings.txt
_dev/.wordlist.dic
_dev/.doctrees/
_dev/update/
_dev/node_modules/

# Vale
.sphinx/styles/*
.sphinx/vale.ini
_dev/styles/*
_dev/vale.ini

# Build outputs
_build
Expand Down
1 change: 0 additions & 1 deletion docs/.sphinx/version

This file was deleted.

158 changes: 80 additions & 78 deletions docs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,23 @@

# 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 ?= $(VENVDIR)/bin/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 = *
REQPDFPACKS = latexmk fonts-freefont-otf texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended texlive-font-utils texlive-lang-cjk texlive-xetex plantuml xindy tex-gyre dvipng
CONFIRM_SUDO ?= N
VALE_CONFIG = $(SPHINXDIR)/vale.ini
VALEDIR ?= $(VENVDIR)/lib/python*/site-packages/vale
VOCAB_CANONICAL = $(SPHINXDIR)/styles/config/vocabularies/Canonical
SPHINX_HOST ?= 127.0.0.1
SPHINX_PORT ?= 8000
DEV_DIR ?= _dev
SPHINX_OPTS ?= -c . -d $(DEV_DIR)/.doctrees -j auto
SPHINX_BUILD ?= $(DOCS_VENVDIR)/bin/sphinx-build
SPHINX_HOST ?= 127.0.0.1
SPHINX_PORT ?= 8000
SPHINX_AUTOBUILD_OPTS ?= -D llms_txt_enabled=0
DOCS_VENVDIR ?= .venv
DOCS_VENV ?= $(DOCS_VENVDIR)/bin/activate
DOCS_SOURCEDIR ?= .
DOCS_BUILDDIR ?= _build
DOCS_PDFPACKAGES ?= latexmk fonts-freefont-otf texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended texlive-font-utils texlive-lang-cjk texlive-xetex plantuml xindy tex-gyre dvipng
DOCS_VOCAB ?= $(DEV_DIR)/styles/config/vocabularies/Canonical
VALE_DIR ?= $(DOCS_VENVDIR)/lib/python*/site-packages/vale
VALE_CONFIG ?= $(DEV_DIR)/vale.ini
PA11Y_CMD ?= $(DEV_DIR)/node_modules/pa11y/bin/pa11y.js --config $(DEV_DIR)/pa11y.json
CONFIRM_SUDO ?= N
CHECK_PATH ?= $(filter-out $(DOCS_VENVDIR) $(DOCS_BUILDDIR) $(DEV_DIR),$(wildcard *))

# Put it first so that "make" without argument is like "make help".
help:
Expand All @@ -37,7 +38,7 @@ 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 <TAB twice>"
@echo "-------------------------------------------------------------"
@echo
Expand All @@ -47,127 +48,128 @@ help:
vale-install pdf-prep pdf-prep-force clean clean-doc \
update lint-md

full-help: $(VENVDIR)
@. $(VENV); $(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
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.
$(VENVDIR):
$(DOCS_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 $(PIPOPTS) --require-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 $(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)
--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) >/dev/null || { \
@test -x $(firstword $(PA11Y_CMD)) >/dev/null || { \
echo "Installing \"pa11y\" from npm..."; echo; \
mkdir -p $(SPHINXDIR)/node_modules/ ; \
npm install --prefix $(SPHINXDIR) pa11y; \
mkdir -p $(DEV_DIR)/node_modules/ ; \
npm install --prefix $(DEV_DIR) pa11y; \
}

pymarkdownlnt-install: install
@. $(VENV); test -d $(VENVDIR)/lib/python*/site-packages/pymarkdown || pip install pymarkdownlnt==0.9.35
@. $(DOCS_VENV); test -d $(DOCS_VENVDIR)/lib/python*/site-packages/pymarkdown || pip install pymarkdownlnt==0.9.35

install: $(VENVDIR)
install: $(DOCS_VENVDIR)

run: install
. $(VENV); $(VENVDIR)/bin/sphinx-autobuild -b dirhtml --host $(SPHINX_HOST) --port $(SPHINX_PORT) "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS)
. $(DOCS_VENV); $(DOCS_VENVDIR)/bin/sphinx-autobuild -b dirhtml --host $(SPHINX_HOST) --port $(SPHINX_PORT) "$(DOCS_SOURCEDIR)" "$(DOCS_BUILDDIR)" $(SPHINX_OPTS) $(SPHINX_AUTOBUILD_OPTS)

# Does not depend on $(BUILDDIR) to rebuild properly at every run.
# Does not depend on $(DOCS_BUILDDIR) to rebuild properly at every run.
html: install
. $(VENV); $(SPHINXBUILD) --fail-on-warning --keep-going -b dirhtml "$(SOURCEDIR)" "$(BUILDDIR)" -w $(SPHINXDIR)/warnings.txt $(SPHINXOPTS)
. $(DOCS_VENV); $(SPHINX_BUILD) --fail-on-warning --keep-going -b dirhtml "$(DOCS_SOURCEDIR)" "$(DOCS_BUILDDIR)" -w $(DEV_DIR)/warnings.txt $(SPHINX_OPTS)

epub: install
. $(VENV); $(SPHINXBUILD) -b epub "$(SOURCEDIR)" "$(BUILDDIR)" -w $(SPHINXDIR)/warnings.txt $(SPHINXOPTS)
. $(DOCS_VENV); $(SPHINX_BUILD) -b epub "$(DOCS_SOURCEDIR)" "$(DOCS_BUILDDIR)" -w $(DEV_DIR)/warnings.txt $(SPHINX_OPTS)

serve: html
cd "$(BUILDDIR)"; python3 -m http.server --bind $(SPHINX_HOST) $(SPHINX_PORT)
cd "$(DOCS_BUILDDIR)"; python3 -m http.server --bind $(SPHINX_HOST) $(SPHINX_PORT)

clean: clean-doc
@test ! -e "$(VENVDIR)" -o -d "$(VENVDIR)" -a "$(abspath $(VENVDIR))" != "$(VENVDIR)"
rm -rf $(VENVDIR)
rm -rf $(SPHINXDIR)/node_modules/
rm -rf $(SPHINXDIR)/styles
@test ! -e "$(DOCS_VENVDIR)" -o -d "$(DOCS_VENVDIR)" -a "$(abspath $(DOCS_VENVDIR))" != "$(DOCS_VENVDIR)"
rm -rf $(DOCS_VENVDIR)
rm -rf $(DEV_DIR)/node_modules/
rm -rf $(DEV_DIR)/styles
rm -rf $(VALE_CONFIG)

clean-doc:
git clean -fx "$(BUILDDIR)"
rm -rf $(SPHINXDIR)/.doctrees
git clean -fx "$(DOCS_BUILDDIR)"
rm -rf $(DEV_DIR)/.doctrees

linkcheck: install
. $(VENV) ; $(SPHINXBUILD) -b linkcheck "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) || { grep --color -F "[broken]" "$(BUILDDIR)/output.txt"; exit 1; }
. $(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 $(BUILDDIR) -name *.html -print0 | xargs -n 1 -0 $(PA11Y)
find $(DOCS_BUILDDIR) -name *.html -print0 | xargs -n 1 -0 $(PA11Y_CMD)

# Without --return-code-scheme explicit, pymarkdownlnt returns 1 for multiple scenarios.
lint-md: pymarkdownlnt-install
@. $(VENV); pymarkdownlnt --config $(SPHINXDIR)/.pymarkdown.json scan --recurse --exclude=$(SPHINXDIR)/** $(SOURCEDIR)
@. $(DOCS_VENV); pymarkdownlnt --config $(DEV_DIR)/.pymarkdown.json --return-code-scheme explicit scan --recurse $(CHECK_PATH); status=$$?; if [ $$status -eq 1 ]; then echo "No Markdown files selected for linting"; exit 0; fi; exit $$status;

vale-install: install
@. $(VENV); test -f $(VALE_CONFIG) || python3 $(SPHINXDIR)/get_vale_conf.py
@echo '.Name=="Canonical.400-Enforce-inclusive-terms"' > $(SPHINXDIR)/styles/woke.filter
@echo '.Level=="error" and .Name!="Canonical.500-Repeated-words" and .Name!="Canonical.000-US-spellcheck"' > $(SPHINXDIR)/styles/error.filter
@echo '.Name=="Canonical.000-US-spellcheck"' > $(SPHINXDIR)/styles/spelling.filter
@. $(VENV); find $(VALEDIR)/vale_bin -size 195c -exec vale --version \;
@. $(DOCS_VENV); test -f $(VALE_CONFIG) || python3 $(DEV_DIR)/get_vale_conf.py
@echo '.Name=="Canonical.400-Enforce-inclusive-terms"' > $(DEV_DIR)/styles/woke.filter
@echo '.Level=="error" and .Name!="Canonical.500-Repeated-words" and .Name!="Canonical.000-US-spellcheck"' > $(DEV_DIR)/styles/error.filter
@echo '.Name=="Canonical.000-US-spellcheck"' > $(DEV_DIR)/styles/spelling.filter
@. $(DOCS_VENV); find $(VALE_DIR)/vale_bin -size 195c -exec vale --version \;

woke: vale-install
@cat $(VOCAB_CANONICAL)/accept.txt > $(VOCAB_CANONICAL)/accept_backup.txt
@cat $(SOURCEDIR)/.custom_wordlist.txt >> $(VOCAB_CANONICAL)/accept.txt
@echo "Running Vale acceptable term check against $(TARGET). To change target set TARGET= with make command"
@. $(VENV); vale --config="$(VALE_CONFIG)" --filter='$(SPHINXDIR)/styles/woke.filter' --glob='*.{md,rst}' $(TARGET)
@cat $(VOCAB_CANONICAL)/accept_backup.txt > $(VOCAB_CANONICAL)/accept.txt && rm $(VOCAB_CANONICAL)/accept_backup.txt
@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='$(DEV_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 $(VOCAB_CANONICAL)/accept.txt > $(VOCAB_CANONICAL)/accept_backup.txt
@cat $(SOURCEDIR)/.custom_wordlist.txt >> $(VOCAB_CANONICAL)/accept.txt
@echo "Running Vale against $(TARGET). To change target set TARGET= with make command"
@. $(VENV); vale --config="$(VALE_CONFIG)" --filter='$(SPHINXDIR)/styles/error.filter' --glob='*.{md,rst}' $(TARGET)
@cat $(VOCAB_CANONICAL)/accept_backup.txt > $(VOCAB_CANONICAL)/accept.txt && rm $(VOCAB_CANONICAL)/accept_backup.txt
@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='$(DEV_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 $(VOCAB_CANONICAL)/accept.txt > $(VOCAB_CANONICAL)/accept_backup.txt
@cat $(SOURCEDIR)/.custom_wordlist.txt >> $(VOCAB_CANONICAL)/accept.txt
@echo "Running Vale against $(TARGET). To change target set TARGET= with make command"
@. $(VENV); vale --config="$(VALE_CONFIG)" --filter='$(SPHINXDIR)/styles/spelling.filter' --glob='*.{md,rst}' $(TARGET)
@cat $(VOCAB_CANONICAL)/accept_backup.txt > $(VOCAB_CANONICAL)/accept.txt && rm $(VOCAB_CANONICAL)/accept_backup.txt
@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='$(DEV_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\`"

pdf-prep: install
@for packageName in $(REQPDFPACKS); do (dpkg-query -W -f='$${Status}' $$packageName 2>/dev/null | \
@for packageName in $(DOCS_PDFPACKAGES); do (dpkg-query -W -f='$${Status}' $$packageName 2>/dev/null | \
grep -c "ok installed" >/dev/null && echo "Package $$packageName is installed") && continue || \
(echo; echo "PDF generation requires the installation of the following packages: $(REQPDFPACKS)" && \
(echo; echo "PDF generation requires the installation of the following packages: $(DOCS_PDFPACKAGES)" && \
echo "" && echo "Run 'sudo make pdf-prep-force' to install these packages" && echo "" && echo \
"Please be aware these packages will be installed to your system") && exit 1 ; done

pdf-prep-force:
apt-get update
apt-get upgrade -y
apt-get install --no-install-recommends -y $(REQPDFPACKS) \
apt-get install --no-install-recommends -y $(DOCS_PDFPACKAGES) \

pdf: pdf-prep
@. $(VENV); sphinx-build -M latexpdf "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS)
@rm ./$(BUILDDIR)/latex/front-page-light.pdf || true
@rm ./$(BUILDDIR)/latex/normal-page-footer.pdf || true
@find ./$(BUILDDIR)/latex -name "*.pdf" -exec mv -t ./$(BUILDDIR) {} +
@rm -r $(BUILDDIR)/latex
@. $(DOCS_VENV); $(SPHINX_BUILD) -M latexpdf "$(DOCS_SOURCEDIR)" "$(DOCS_BUILDDIR)" $(SPHINX_OPTS)
@rm ./$(DOCS_BUILDDIR)/latex/front-page-light.pdf || true
@rm ./$(DOCS_BUILDDIR)/latex/normal-page-footer.pdf || true
@find ./$(DOCS_BUILDDIR)/latex -name "*.pdf" -exec mv -t ./$(DOCS_BUILDDIR) {} +
@rm -r $(DOCS_BUILDDIR)/latex
@echo
@echo "Output can be found in ./$(BUILDDIR)"
@echo "Output can be found in ./$(DOCS_BUILDDIR)"
@echo

update: install
@. $(VENV); .sphinx/update_sp.py
@. $(DOCS_VENV); _dev/update_sp.py

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
# "make mode" option. $(O) is meant as a shortcut for $(SPHINX_OPTS).
%:
$(MAKE) --no-print-directory install
. $(VENV); $(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
. $(DOCS_VENV); $(SPHINX_BUILD) -M $@ "$(DOCS_SOURCEDIR)" "$(DOCS_BUILDDIR)" $(SPHINX_OPTS) $(O)
File renamed without changes.
File renamed without changes.
Loading
Loading