+ {% endif %}
+
{% if github_url and github_version and github_folder %}
{% if github_issues %}
diff --git a/docs/.sphinx/_templates/sidebar/search.html b/docs/.sphinx/_templates/sidebar/search.html
new file mode 100644
index 000000000..644a5ef6a
--- /dev/null
+++ b/docs/.sphinx/_templates/sidebar/search.html
@@ -0,0 +1,7 @@
+
+
diff --git a/docs/.sphinx/build_requirements.py b/docs/.sphinx/build_requirements.py
new file mode 100644
index 000000000..1a317bb07
--- /dev/null
+++ b/docs/.sphinx/build_requirements.py
@@ -0,0 +1,131 @@
+import sys
+import os
+
+import pathlib
+scriptdir=pathlib.Path(__file__).parent.resolve()
+sys.path.append(scriptdir)
+
+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")
+
+ 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")
+ requirements.append("linkify-it-py")
+
+ # removes duplicate entries
+ requirements = list(dict.fromkeys(requirements))
+ requirements.sort()
+
+ with open(os.path.join(scriptdir, "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/docs/.sphinx/conf.py b/docs/.sphinx/conf.py
new file mode 120000
index 000000000..d026d1f6b
--- /dev/null
+++ b/docs/.sphinx/conf.py
@@ -0,0 +1 @@
+../conf.py
\ No newline at end of file
diff --git a/docs/.sphinx/custom_conf.py b/docs/.sphinx/custom_conf.py
new file mode 120000
index 000000000..8c6c81020
--- /dev/null
+++ b/docs/.sphinx/custom_conf.py
@@ -0,0 +1 @@
+../custom_conf.py
\ No newline at end of file
diff --git a/docs/.sphinx/get_vale_conf.py b/docs/.sphinx/get_vale_conf.py
new file mode 100644
index 000000000..2f1c566f9
--- /dev/null
+++ b/docs/.sphinx/get_vale_conf.py
@@ -0,0 +1,29 @@
+#! /usr/bin/env python
+
+import requests
+import os
+
+DIR=os.getcwd()
+
+def main():
+
+ if os.path.exists(f"{DIR}/.sphinx/styles/Canonical"):
+ print("Vale directory exists")
+ else:
+ os.makedirs(f"{DIR}/.sphinx/styles/Canonical")
+
+ 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()
+
+ 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
diff --git a/docs/.sphinx/pa11y.json b/docs/.sphinx/pa11y.json
new file mode 100644
index 000000000..8df0cb9cb
--- /dev/null
+++ b/docs/.sphinx/pa11y.json
@@ -0,0 +1,9 @@
+{
+ "chromeLaunchConfig": {
+ "args": [
+ "--no-sandbox"
+ ]
+ },
+ "reporter": "cli",
+ "standard": "WCAG2AA"
+}
\ No newline at end of file
diff --git a/docs/.sphinx/requirements.txt b/docs/.sphinx/requirements.txt
deleted file mode 100644
index f5a1d8c38..000000000
--- a/docs/.sphinx/requirements.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-furo
-linkify-it-py
-lxd-sphinx-extensions
-myst-parser
-pyspelling
-sphinx
-sphinx-autobuild
-sphinx-copybutton
-sphinx-design
-sphinx-notfound-page
-sphinx-reredirects
-sphinx-tabs
-sphinxcontrib-jquery
-sphinxext-opengraph
diff --git a/docs/.sphinx/spellingcheck.yaml b/docs/.sphinx/spellingcheck.yaml
index 5d85d157a..c0f7e0397 100644
--- a/docs/.sphinx/spellingcheck.yaml
+++ b/docs/.sphinx/spellingcheck.yaml
@@ -27,3 +27,4 @@ matrix:
- div.visually-hidden
- img
- a.p-navigation__link
+ - a.contributor
diff --git a/docs/.wordlist.txt b/docs/.wordlist.txt
index 416f24cd9..e205c6feb 100644
--- a/docs/.wordlist.txt
+++ b/docs/.wordlist.txt
@@ -1,39 +1,54 @@
+# 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
-dropdown
Diátaxis
+dropdown
EBS
EKS
+enablement
favicon
Furo
+Git
+GitHub
Grafana
IAM
installable
JSON
Juju
-Kubernetes
Kubeflow
-libkrb
+Kubernetes
+Launchpad
+linter
+LTS
Makefile
+Matrix
+Mattermost
MyST
namespace
namespaces
NodePort
+Numbat
observability
+OEM
OLM
Permalink
pre
+Quickstart
ReadMe
reST
reStructuredText
RTD
subdirectories
-subtree
subfolders
+subtree
+Ubuntu
UI
+UUID
VM
YAML
diff --git a/docs/Makefile b/docs/Makefile
index b6f4a0a5a..a861ba84a 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -1,89 +1,30 @@
-# Minimal makefile for Sphinx documentation
+# 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 set these variables from the command line, and also
-# from the environment for the first two.
-SPHINXOPTS ?= -c . -d .sphinx/.doctrees
-SPHINXBUILD ?= sphinx-build
-SPHINXDIR = .sphinx
-SOURCEDIR = .
-BUILDDIR = _build
-VENVDIR = $(SPHINXDIR)/venv
-VENV = $(VENVDIR)/bin/activate
-
-.PHONY: help woke-install install run html epub serve clean clean-doc \
- spelling linkcheck woke Makefile
+# 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.
# Put it first so that "make" without argument is like "make help".
-help: $(VENVDIR)
- @. $(VENV); $(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
-
-# Explicit target avoids fall-through to the "Makefile" target.
-$(SPHINXDIR)/requirements.txt:
- test -f $(SPHINXDIR)/requirements.txt
-
-# If requirements are updated, venv should be rebuilt and timestamped.
-$(VENVDIR): $(SPHINXDIR)/requirements.txt
- @echo "... setting up virtualenv"
- python3 -m venv $(VENVDIR)
- . $(VENV); pip install --require-virtualenv \
- --upgrade -r $(SPHINXDIR)/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
+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 inclusive language: make woke \n" \
- "* other possible targets: make \n" \
- "--------------------------------------------------------------- \n"
- @touch $(VENVDIR)
-
-woke-install:
- @type woke >/dev/null 2>&1 || \
- { echo "Installing \"woke\" snap... \n"; sudo snap install woke; }
-
-install: $(VENVDIR) woke-install
-
-run: install
- . $(VENV); sphinx-autobuild --re-ignore 'reference/policies/.*/index.md' -b dirhtml "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS)
-
-# Doesn't depend on $(BUILDDIR) to rebuild properly at every run.
-html: install
- . $(VENV); $(SPHINXBUILD) -b dirhtml "$(SOURCEDIR)" "$(BUILDDIR)" -w .sphinx/warnings.txt $(SPHINXOPTS)
-
-epub: install
- . $(VENV); $(SPHINXBUILD) -b epub "$(SOURCEDIR)" "$(BUILDDIR)" -w .sphinx/warnings.txt $(SPHINXOPTS)
-
-serve: html
- cd "$(BUILDDIR)"; python3 -m http.server 8000
-
-clean: clean-doc
- @test ! -e "$(VENVDIR)" -o -d "$(VENVDIR)" -a "$(abspath $(VENVDIR))" != "$(VENVDIR)"
- rm -rf $(VENVDIR)
- rm -rf .sphinx/.doctrees
-
-clean-doc:
- git clean -fx "$(BUILDDIR)"
-
-spelling: html
- . $(VENV) ; python3 -m pyspelling -c .sphinx/spellingcheck.yaml
-
-linkcheck: install
- . $(VENV) ; $(SPHINXBUILD) -b linkcheck "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS)
-
-woke: woke-install
- woke *.rst **/*.rst --exit-1-on-failure \
- -c https://github.com/canonical/Inclusive-naming/raw/main/config.yml
-
-# Catch-all target: route all unknown targets to Sphinx using the new
-# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
-%: Makefile
- . $(VENV); $(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+ "------------------------------------------------------------- \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" \
+ "* other possible targets: make \n" \
+ "------------------------------------------------------------- \n"
+
+%:
+ $(MAKE) -f Makefile.sp sp-$@
diff --git a/docs/Makefile.sp b/docs/Makefile.sp
new file mode 100644
index 000000000..d40405976
--- /dev/null
+++ b/docs/Makefile.sp
@@ -0,0 +1,122 @@
+# 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."
+
+# 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 \
+ $(PIPOPTS) --require-virtualenv $(ADDPREREQS); \
+ fi
+ . $(VENV); python3 $(SPHINXDIR)/build_requirements.py
+
+# If requirements are updated, venv should be rebuilt and timestamped.
+$(VENVDIR): $(SPHINXDIR)/requirements.txt
+ @echo "... setting up virtualenv"
+ python3 -m venv $(VENVDIR)
+ . $(VENV); pip install $(PIPOPTS) --require-virtualenv \
+ --upgrade -r $(SPHINXDIR)/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 -f $(SPHINXDIR)/requirements.txt
+ 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/docs/conf.py b/docs/conf.py
index 3292d8121..e0c23fdd7 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,7 +1,14 @@
import sys
+import os
+import requests
+from urllib.parse import urlparse
+from git import Repo, InvalidGitRepositoryError
+import time
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
@@ -17,42 +24,65 @@
extensions = [
'sphinx_design',
- 'sphinx_tabs.tabs',
- 'sphinx_reredirects',
- 'youtube-links',
- 'related-links',
- 'custom-rst-roles',
- 'terminal-output',
'sphinx_copybutton',
- 'sphinxext.opengraph',
- 'myst_parser',
'sphinxcontrib.jquery',
- 'notfound.extension'
]
+
+# 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
-# Additional MyST syntax
-myst_enable_extensions = [
- 'substitution',
- 'deflist',
- 'linkify'
-]
-myst_enable_extensions.extend(custom_myst_extensions)
-
# Used for related links
if not 'discourse_prefix' in html_context and 'discourse' in html_context:
html_context['discourse_prefix'] = html_context['discourse'] + '/t/'
-# The default for notfound_urls_prefix usually works, but not for
-# documentation on documentation.ubuntu.com
+# 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 = ''
+
+# 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('/')
+
+ if len(url_parts) >= 2 and 'READTHEDOCS_VERSION' in os.environ and os.environ['READTHEDOCS_VERSION'] == url_parts[-2]:
+ url_version = url_parts[-2] + '/'
+
+ if len(url_parts) >= 3 and 'READTHEDOCS_LANGUAGE' in os.environ and os.environ['READTHEDOCS_LANGUAGE'] == url_parts[-3]:
+ url_lang = url_parts[-3] + '/'
+
+# Set notfound_urls_prefix to the slug (if defined) and the version/language affix
if slug:
- notfound_urls_prefix = '/' + slug + '/en/latest/'
+ 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 = ''
notfound_context = {
'title': 'Page not found',
- 'body': '
Page not found
\n\n
Sorry, but the documentation page that you are looking for was not found.
\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',
+ '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',
}
# Default image for OGP (to prevent font errors, see
@@ -96,6 +126,10 @@
for tag in custom_tags:
tags.add(tag)
+# html_context['get_contribs'] is a function and cannot be
+# cached (see https://github.com/sphinx-doc/sphinx/issues/12300)
+suppress_warnings = ["config.cache"]
+
############################################################
### Styling
############################################################
@@ -108,6 +142,7 @@
# Setting templates_path for epub makes the build fail
if builder == 'dirhtml' or builder == 'html':
templates_path = ['.sphinx/_templates']
+ notfound_template = '404.html'
# Theme configuration
html_theme = 'furo'
@@ -129,11 +164,50 @@
'custom.css',
'header.css',
'github_issue_links.css',
- 'furo_colors.css'
+ 'furo_colors.css',
+ 'footer.css'
]
html_css_files.extend(custom_html_css_files)
-html_js_files = ['header-nav.js']
+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
+#############################################################
diff --git a/docs/custom_conf.py b/docs/custom_conf.py
index 5d2d88ab6..d26d27d85 100644
--- a/docs/custom_conf.py
+++ b/docs/custom_conf.py
@@ -19,7 +19,7 @@
############################################################
# Product name
-project = 'Active Directory GPO support'
+project = 'Active Directory GPO client'
author = 'Canonical Group Ltd'
# The title you want to display for the documentation in the sidebar.
@@ -27,7 +27,14 @@
# To not display any title, set this option to an empty string.
html_title = project + ' documentation'
-# The default value uses the current year as the copyright year.
+# The default value uses CC-BY-SA as the license and the current year
+# as the copyright year.
+#
+# If your documentation needs a different copyright license, use that
+# instead of 'CC-BY-SA'. Also, if your documentation is included as
+# part of the code repository of your project, it'll inherit the license
+# of the code. So you'll need to specify that license here (instead of
+# 'CC-BY-SA').
#
# 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
@@ -41,13 +48,15 @@
# -H 'Accept: application/vnd.github.v3.raw' \
# https://api.github.com/repos/canonical/ | jq '.created_at'
-copyright = '%s, %s' % (datetime.date.today().year, author)
+copyright = '%s CC-BY-SA, %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)
-ogp_site_url = 'https://canonical-starter-pack.readthedocs-hosted.com/'
+# 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://canonical-adsys.readthedocs-hosted.com/'
# 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
@@ -65,7 +74,7 @@
# 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': 'documentation.ubuntu.com',
+ 'product_page': 'github.com/ubuntu/adsys',
# 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")
@@ -75,9 +84,18 @@
# 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',
+ # 'discourse': 'https://discourse.ubuntu.com',
+
+ # Change to the Mattermost channel you want to link to
+ # (use an empty value if you don't want to link)
+ # 'mattermost': 'https://chat.canonical.com/canonical/channels/documentation',
+
+ # Change to the Matrix channel you want to link to
+ # (use an empty value if you don't want to link)
+ # 'matrix': 'https://matrix.to/#/#documentation:ubuntu.com',
- # Change to the GitHub info for your project
+ # 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/ubuntu/adsys',
# Change to the branch for this version of the documentation
@@ -93,7 +111,13 @@
# Controls the existence of Previous / Next buttons at the bottom of pages
# Valid options: none, prev, next, both
- 'sequential_nav': "none"
+ 'sequential_nav': "none",
+
+ # 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
@@ -106,7 +130,10 @@
# 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.
redirects = {}
############################################################
@@ -114,16 +141,14 @@
############################################################
# Links to ignore when checking links
-
linkcheck_ignore = [
- 'http://127.0.0.1:8000'
+ 'http://127.0.0.1:8000',
+ 'https://leonelson.com/2011/08/15/how-to-increase-your-csr-key-size-on-microsoft-iis-without-removing-the-production-certificate/',
]
# Pages on which to ignore anchors
# (This list will be appended to linkcheck_anchors_ignore_for_url)
-
-custom_linkcheck_anchors_ignore_for_url = [
- ]
+custom_linkcheck_anchors_ignore_for_url = []
############################################################
### Additions to default configuration
@@ -132,14 +157,36 @@
## The following settings are appended to the default configuration.
## Use them to extend the default functionality.
-# Add extensions
-custom_extensions = []
-
-# Add MyST extensions
+# 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'
+ ]
+
+# 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 = []
+
# Add files or directories that should be excluded from processing.
-custom_excludes = []
+custom_excludes = [
+ 'doc-cheat-sheet*',
+ ]
# Add CSS files (located in .sphinx/_static/)
custom_html_css_files = []
@@ -162,15 +209,25 @@
# (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.
-
def run_before_build(app):
import subprocess
subprocess.run(['./make_toctree.sh', 'reference/policies/Computer Policies', 'reference/policies/User Policies'])
def setup(app):
app.connect('builder-inited', run_before_build)
+
+
+# Define a :center: role that can be used to center the content of table cells.
+rst_prolog = '''
+.. role:: center
+ :class: align-center
+'''