We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Move changelog to docs website
I suggest we make the changelog become part of the rendered documentation instead of a dedicated markdown file to be read from GitHub, and that we let CHANGELOG.md point to this rendered view.

Note for reference that jupyterhub/jupyterhub repo only has rendered website documentation currently, [see it here](https://jupyterhub.readthedocs.io/en/stable/changelog.html).

![image](https://user-images.githubusercontent.com/3837114/119242003-c4e93280-bb5a-11eb-9fdf-c951204624bc.png)

---

I think there are two key benefits of this:
1. We can get navigation assistance out of the box
2. We can make use of myst formatting, such as note/warning callouts

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `docs/source/conf.py`
Content:
```
1 # Configuration file for Sphinx to build our documentation to HTML.
2 #
3 # Configuration reference: https://www.sphinx-doc.org/en/master/usage/configuration.html
4 #
5 
6 # -- Path setup --------------------------------------------------------------
7 
8 # If extensions (or modules to document with autodoc) are in another directory,
9 # add these directories to sys.path here. If the directory is relative to the
10 # documentation root, use os.path.abspath to make it absolute, like shown here.
11 #
12 # import os
13 # import sys
14 # sys.path.insert(0, os.path.abspath('.'))
15 
16 
17 # -- Project specific imports ------------------------------------------------
18 
19 import datetime
20 import os
21 import re
22 import subprocess
23 
24 import yaml
25 
26 # -- Sphinx setup function ---------------------------------------------------
27 # ref: http://www.sphinx-doc.org/en/latest/extdev/tutorial.html#the-setup-function
28 
29 
30 def setup(app):
31     app.add_css_file("custom.css")
32 
33 
34 # -- Referencable variables --------------------------------------------------
35 
36 
37 def _get_git_ref_from_chartpress_based_version(version):
38     """
39     Get a git ref from a chartpress set version of format like
40     1.2.3-beta.1.n123.h1234567, 1.2.3-n123.h1234567, or 1.2.3.
41     """
42     tag_hash_split = re.split(r"[\.|-]n\d\d\d\.h", version)
43     if len(tag_hash_split) == 2:
44         return tag_hash_split[1]
45     else:
46         return tag_hash_split[0]
47 
48 
49 # FIXME: Stop relying on chartpress to modify Chart.yaml (and values.yaml) by
50 #        creating a new feature of chartpress that allows us to directly acquire
51 #        the dynamically set chart version from Chart.yaml. This would be
52 #        similar to the --list-images feature of chartpress.
53 subprocess.run(["chartpress", "--skip-build"], cwd=os.path.abspath("../.."))
54 with open("../../jupyterhub/Chart.yaml") as f:
55     chart = yaml.safe_load(f)
56 subprocess.run(["chartpress", "--reset"], cwd=os.path.abspath("../.."))
57 
58 # These substitution variables only work in markdown contexts, and does not work
59 # within links etc. Reference using {{ variable_name }}
60 #
61 # myst_substitutions ref: https://myst-parser.readthedocs.io/en/latest/using/syntax-optional.html#substitutions-with-jinja2
62 myst_substitutions = {
63     "chart_version": chart["version"],
64     "jupyterhub_version": chart["appVersion"],
65     # FIXME: kubeVersion contain >=, but by having > in the string we substitute
66     #        we run into this issue:
67     #        https://github.com/executablebooks/MyST-Parser/issues/282
68     "kube_version": chart["kubeVersion"].split("-", 1)[0][2:],
69     "helm_version": "3.5",
70     "requirements": f"[hub/images/requirements.txt](https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/{_get_git_ref_from_chartpress_based_version(chart['version'])}/images/hub/requirements.txt)",
71 }
72 
73 
74 # -- General MyST configuration -----------------------------------------------------
75 
76 # myst_enable_extensions ref: https://myst-parser.readthedocs.io/en/latest/using/syntax-optional.html
77 myst_enable_extensions = [
78     "substitution",
79 ]
80 
81 
82 # -- Project information -----------------------------------------------------
83 # ref: https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
84 
85 project = "Zero to JupyterHub with Kubernetes"
86 copyright = f"{datetime.date.today().year}, Project Jupyter Contributors"
87 author = "Project Jupyter Contributors"
88 
89 
90 # -- General Sphinx configuration ---------------------------------------------------
91 # ref: https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
92 
93 # Set the default role so we can use `foo` instead of ``foo``
94 default_role = "literal"
95 
96 # Add any Sphinx extension module names here, as strings. They can be
97 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
98 # ones.
99 extensions = [
100     "sphinx.ext.mathjax",
101     "sphinx_copybutton",
102     "myst_parser",
103     "sphinxext.rediraffe",
104     "sphinxext.opengraph",
105 ]
106 
107 # List of patterns, relative to source directory, that match files and
108 # directories to ignore when looking for source files.
109 # This pattern also affects html_static_path and html_extra_path.
110 exclude_patterns = []
111 
112 # The root toctree document.
113 root_doc = master_doc = "index"
114 
115 # The suffix(es) of source filenames.
116 source_suffix = [".md", ".rst"]
117 
118 # Rediraffe redirects to ensure proper redirection
119 rediraffe_redirects = {
120     "customizing/user-management": "jupyterhub/customizing/user-management",
121     "customizing/user-storage": "jupyterhub/customizing/user-storage",
122     "customizing/user-resources": "jupyterhub/customizing/user-resources",
123     "customizing/user-environment": "jupyterhub/customizing/user-environment",
124     "customizing/extending-jupyterhub": "jupyterhub/customizing/extending-jupyterhub",
125     "reference/glossary": "resources/glossary",
126     "reference/tools": "resources/tools",
127     "reference/reference-docs": "resources/reference-docs",
128     "reference/reference": "resources/reference",
129     "community/additional-resources": "resources/community",
130     "community/users-list": "resources/community",
131     "community/tips": "resources/community",
132     "setup-jupyterhub/turn-off": "jupyterhub/uninstall",
133     "setup-jupyterhub/setup-jupyterhub": "jupyterhub/installation",
134     "setup-jupyterhub/setup-helm": "kubernetes/setup-helm",
135     "ovh/step-zero-ovh": "kubernetes/ovh/step-zero-ovh",
136     "digital-ocean/step-zero-digital-ocean": "kubernetes/digital-ocean/step-zero-digital-ocean",
137     "ibm/step-zero-ibm": "kubernetes/ibm/step-zero-ibm",
138     "redhat/step-zero-openshift": "kubernetes/redhat/step-zero-openshift",
139     "amazon/step-zero-aws-eks": "kubernetes/amazon/step-zero-aws-eks",
140     "amazon/step-zero-aws": "kubernetes/amazon/step-zero-aws",
141     "microsoft/step-zero-azure-autoscale": "kubernetes/microsoft/step-zero-azure-autoscale",
142     "microsoft/step-zero-azure": "kubernetes/microsoft/step-zero-azure",
143     "google/step-zero-gcp": "kubernetes/google/step-zero-gcp",
144     "create-k8s-cluster": "kubernetes/setup-kubernetes",
145     "turn-off": "jupyterhub/uninstall",
146     "setup-jupyterhub": "jupyterhub/index",
147     "setup-helm": "kubernetes/setup-helm",
148     "index-setup-jupyterhub": "jupyterhub/index",
149     "tools": "reference/tools",
150     "reference-docs": "reference/reference-docs",
151     "index-reference": "resources/reference",
152     "glossary": "reference/glossary",
153     "user-storage": "customizing/user-storage",
154     "user-resources": "customizing/user-resources",
155     "user-management": "customizing/user-management",
156     "user-environment": "customizing/user-environment",
157     "index-customization-guide": "jupyterhub/customization",
158     "extending-jupyterhub": "customizing/extending-jupyterhub",
159     "users-list": "community/users-list",
160     "tips": "community/tips",
161     "index-community-resources": "resources/community",
162     "additional-resources": "resources/community",
163     "upgrading": "administrator/upgrading",
164     "troubleshooting": "administrator/troubleshooting",
165     "security": "administrator/security",
166     "optimization": "administrator/optimization",
167     "index-administrator-guide": "administrator/index",
168     "debug": "administrator/debug",
169     "cost": "administrator/cost",
170     "authentication": "administrator/authentication",
171     "architecture": "administrator/architecture",
172     "advanced": "administrator/advanced",
173 }
174 
175 # opengraph configuration
176 # ogp_site_url/prefix is set automatically by RTD
177 ogp_image = "_static/logo.png"
178 ogp_use_first_image = True
179 
180 # -- Generate the Helm chart configuration reference from a schema file ------
181 
182 # header
183 with open("resources/reference.txt") as f:
184     header_md = f.readlines()
185 header_md = header_md[1:]
186 header_md = [ln.strip("\n") for ln in header_md]
187 
188 # schema
189 with open("../../jupyterhub/schema.yaml") as f:
190     data = yaml.safe_load(f)
191 
192 
193 def parse_schema(d, md=[], depth=0, pre=""):
194     """
195     Generate markdown headers from a passed python dictionary created by
196     parsing a schema.yaml file.
197     """
198     if "then" in d:
199         d = d["then"]
200 
201     if "properties" in d:
202         depth += 1
203         # Create markdown headers for each schema level
204         for key, val in d["properties"].items():
205             md.append(f"(schema_{pre}{key})=")
206             md.append("#" * (depth + 1) + f" {pre}{key}")
207             md.append("")
208             if "description" in val:
209                 for ln in val["description"].split("\n"):
210                     md.append(ln)
211                 md.append("")
212 
213             parse_schema(val, md, depth, f"{pre}{key}.")
214         depth -= 1
215     return md
216 
217 
218 schema_md = parse_schema(data)
219 
220 # reference = header + schema
221 reference_md = header_md + schema_md
222 with open("resources/reference.md", "w") as f:
223     f.write("\n".join(reference_md))
224 
225 
226 # -- Options for linkcheck builder -------------------------------------------
227 # ref: http://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-the-linkcheck-builder
228 linkcheck_ignore = [
229     r"(.*)github\.com(.*)#",  # javascript based anchors
230     r"(.*)/#%21(.*)/(.*)",  # /#!forum/jupyter - encoded anchor edge case
231     "https://your-domain.com",  # example
232     "https://your-domain-name.com",  # example
233     "https://kubernetes.io/docs/tutorials/kubernetes-basics/",  # works
234     "https://cloud.ibm.com/kubernetes/catalog/create",  # works
235     "https://portal.azure.com",  # sign-in redirect noise
236     "https://console.cloud.google.com",  # sign-in redirect noise
237     "https://console.developers.google.com",  # sign-in redirect noise
238 ]
239 linkcheck_anchors_ignore = [
240     "/#!",
241     "/#%21",
242 ]
243 
244 
245 # -- Options for HTML output -------------------------------------------------
246 # ref: http://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
247 
248 # The theme to use for HTML and HTML Help pages.  See the documentation for
249 # a list of builtin themes.
250 #
251 
252 html_theme = "pydata_sphinx_theme"
253 html_theme_options = {
254     "github_url": "https://github.com/jupyterhub/zero-to-jupyterhub-k8s/",
255     "use_edit_page_button": True,
256 }
257 html_context = {
258     "github_user": "jupyterhub",
259     "github_repo": "zero-to-jupyterhub-k8s",
260     "github_version": "main",
261     "doc_path": "docs/source",
262 }
263 
264 html_favicon = "_static/images/logo/favicon.ico"
265 html_logo = "_static/images/logo/logo.png"
266 
267 # Add any paths that contain custom static files (such as style sheets) here,
268 # relative to this directory. They are copied after the builtin static files,
269 # so a file named "default.css" will overwrite the builtin "default.css".
270 html_static_path = ["_static"]
271
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/docs/source/conf.py b/docs/source/conf.py
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -228,6 +228,9 @@
 linkcheck_ignore = [
     r"(.*)github\.com(.*)#",  # javascript based anchors
     r"(.*)/#%21(.*)/(.*)",  # /#!forum/jupyter - encoded anchor edge case
+    r"https://github.com/[^/]*$",  # too many github usernames / searches in changelog
+    "https://github.com/jupyterhub/zero-to-jupyterhub-k8s/pull/",  # too many PRs in changelog
+    "https://github.com/jupyterhub/zero-to-jupyterhub-k8s/compare/",  # too many comparisons in changelog
     "https://your-domain.com",  # example
     "https://your-domain-name.com",  # example
     "https://kubernetes.io/docs/tutorials/kubernetes-basics/",  # works

{"golden_diff": "diff --git a/docs/source/conf.py b/docs/source/conf.py\n--- a/docs/source/conf.py\n+++ b/docs/source/conf.py\n@@ -228,6 +228,9 @@\n linkcheck_ignore = [\n     r\"(.*)github\\.com(.*)#\",  # javascript based anchors\n     r\"(.*)/#%21(.*)/(.*)\",  # /#!forum/jupyter - encoded anchor edge case\n+    r\"https://github.com/[^/]*$\",  # too many github usernames / searches in changelog\n+    \"https://github.com/jupyterhub/zero-to-jupyterhub-k8s/pull/\",  # too many PRs in changelog\n+    \"https://github.com/jupyterhub/zero-to-jupyterhub-k8s/compare/\",  # too many comparisons in changelog\n     \"https://your-domain.com\",  # example\n     \"https://your-domain-name.com\",  # example\n     \"https://kubernetes.io/docs/tutorials/kubernetes-basics/\",  # works\n", "issue": "Move changelog to docs website\nI suggest we make the changelog become part of the rendered documentation instead of a dedicated markdown file to be read from GitHub, and that we let CHANGELOG.md point to this rendered view.\r\n\r\nNote for reference that jupyterhub/jupyterhub repo only has rendered website documentation currently, [see it here](https://jupyterhub.readthedocs.io/en/stable/changelog.html).\r\n\r\n![image](https://user-images.githubusercontent.com/3837114/119242003-c4e93280-bb5a-11eb-9fdf-c951204624bc.png)\r\n\r\n---\r\n\r\nI think there are two key benefits of this:\r\n1. We can get navigation assistance out of the box\r\n2. We can make use of myst formatting, such as note/warning callouts\n", "before_files": [{"content": "# Configuration file for Sphinx to build our documentation to HTML.\n#\n# Configuration reference: https://www.sphinx-doc.org/en/master/usage/configuration.html\n#\n\n# -- Path setup --------------------------------------------------------------\n\n# If extensions (or modules to document with autodoc) are in another directory,\n# add these directories to sys.path here. If the directory is relative to the\n# documentation root, use os.path.abspath to make it absolute, like shown here.\n#\n# import os\n# import sys\n# sys.path.insert(0, os.path.abspath('.'))\n\n\n# -- Project specific imports ------------------------------------------------\n\nimport datetime\nimport os\nimport re\nimport subprocess\n\nimport yaml\n\n# -- Sphinx setup function ---------------------------------------------------\n# ref: http://www.sphinx-doc.org/en/latest/extdev/tutorial.html#the-setup-function\n\n\ndef setup(app):\n    app.add_css_file(\"custom.css\")\n\n\n# -- Referencable variables --------------------------------------------------\n\n\ndef _get_git_ref_from_chartpress_based_version(version):\n    \"\"\"\n    Get a git ref from a chartpress set version of format like\n    1.2.3-beta.1.n123.h1234567, 1.2.3-n123.h1234567, or 1.2.3.\n    \"\"\"\n    tag_hash_split = re.split(r\"[\\.|-]n\\d\\d\\d\\.h\", version)\n    if len(tag_hash_split) == 2:\n        return tag_hash_split[1]\n    else:\n        return tag_hash_split[0]\n\n\n# FIXME: Stop relying on chartpress to modify Chart.yaml (and values.yaml) by\n#        creating a new feature of chartpress that allows us to directly acquire\n#        the dynamically set chart version from Chart.yaml. This would be\n#        similar to the --list-images feature of chartpress.\nsubprocess.run([\"chartpress\", \"--skip-build\"], cwd=os.path.abspath(\"../..\"))\nwith open(\"../../jupyterhub/Chart.yaml\") as f:\n    chart = yaml.safe_load(f)\nsubprocess.run([\"chartpress\", \"--reset\"], cwd=os.path.abspath(\"../..\"))\n\n# These substitution variables only work in markdown contexts, and does not work\n# within links etc. Reference using {{ variable_name }}\n#\n# myst_substitutions ref: https://myst-parser.readthedocs.io/en/latest/using/syntax-optional.html#substitutions-with-jinja2\nmyst_substitutions = {\n    \"chart_version\": chart[\"version\"],\n    \"jupyterhub_version\": chart[\"appVersion\"],\n    # FIXME: kubeVersion contain >=, but by having > in the string we substitute\n    #        we run into this issue:\n    #        https://github.com/executablebooks/MyST-Parser/issues/282\n    \"kube_version\": chart[\"kubeVersion\"].split(\"-\", 1)[0][2:],\n    \"helm_version\": \"3.5\",\n    \"requirements\": f\"[hub/images/requirements.txt](https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/{_get_git_ref_from_chartpress_based_version(chart['version'])}/images/hub/requirements.txt)\",\n}\n\n\n# -- General MyST configuration -----------------------------------------------------\n\n# myst_enable_extensions ref: https://myst-parser.readthedocs.io/en/latest/using/syntax-optional.html\nmyst_enable_extensions = [\n    \"substitution\",\n]\n\n\n# -- Project information -----------------------------------------------------\n# ref: https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information\n\nproject = \"Zero to JupyterHub with Kubernetes\"\ncopyright = f\"{datetime.date.today().year}, Project Jupyter Contributors\"\nauthor = \"Project Jupyter Contributors\"\n\n\n# -- General Sphinx configuration ---------------------------------------------------\n# ref: https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration\n\n# Set the default role so we can use `foo` instead of ``foo``\ndefault_role = \"literal\"\n\n# Add any Sphinx extension module names here, as strings. They can be\n# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom\n# ones.\nextensions = [\n    \"sphinx.ext.mathjax\",\n    \"sphinx_copybutton\",\n    \"myst_parser\",\n    \"sphinxext.rediraffe\",\n    \"sphinxext.opengraph\",\n]\n\n# List of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\n# This pattern also affects html_static_path and html_extra_path.\nexclude_patterns = []\n\n# The root toctree document.\nroot_doc = master_doc = \"index\"\n\n# The suffix(es) of source filenames.\nsource_suffix = [\".md\", \".rst\"]\n\n# Rediraffe redirects to ensure proper redirection\nrediraffe_redirects = {\n    \"customizing/user-management\": \"jupyterhub/customizing/user-management\",\n    \"customizing/user-storage\": \"jupyterhub/customizing/user-storage\",\n    \"customizing/user-resources\": \"jupyterhub/customizing/user-resources\",\n    \"customizing/user-environment\": \"jupyterhub/customizing/user-environment\",\n    \"customizing/extending-jupyterhub\": \"jupyterhub/customizing/extending-jupyterhub\",\n    \"reference/glossary\": \"resources/glossary\",\n    \"reference/tools\": \"resources/tools\",\n    \"reference/reference-docs\": \"resources/reference-docs\",\n    \"reference/reference\": \"resources/reference\",\n    \"community/additional-resources\": \"resources/community\",\n    \"community/users-list\": \"resources/community\",\n    \"community/tips\": \"resources/community\",\n    \"setup-jupyterhub/turn-off\": \"jupyterhub/uninstall\",\n    \"setup-jupyterhub/setup-jupyterhub\": \"jupyterhub/installation\",\n    \"setup-jupyterhub/setup-helm\": \"kubernetes/setup-helm\",\n    \"ovh/step-zero-ovh\": \"kubernetes/ovh/step-zero-ovh\",\n    \"digital-ocean/step-zero-digital-ocean\": \"kubernetes/digital-ocean/step-zero-digital-ocean\",\n    \"ibm/step-zero-ibm\": \"kubernetes/ibm/step-zero-ibm\",\n    \"redhat/step-zero-openshift\": \"kubernetes/redhat/step-zero-openshift\",\n    \"amazon/step-zero-aws-eks\": \"kubernetes/amazon/step-zero-aws-eks\",\n    \"amazon/step-zero-aws\": \"kubernetes/amazon/step-zero-aws\",\n    \"microsoft/step-zero-azure-autoscale\": \"kubernetes/microsoft/step-zero-azure-autoscale\",\n    \"microsoft/step-zero-azure\": \"kubernetes/microsoft/step-zero-azure\",\n    \"google/step-zero-gcp\": \"kubernetes/google/step-zero-gcp\",\n    \"create-k8s-cluster\": \"kubernetes/setup-kubernetes\",\n    \"turn-off\": \"jupyterhub/uninstall\",\n    \"setup-jupyterhub\": \"jupyterhub/index\",\n    \"setup-helm\": \"kubernetes/setup-helm\",\n    \"index-setup-jupyterhub\": \"jupyterhub/index\",\n    \"tools\": \"reference/tools\",\n    \"reference-docs\": \"reference/reference-docs\",\n    \"index-reference\": \"resources/reference\",\n    \"glossary\": \"reference/glossary\",\n    \"user-storage\": \"customizing/user-storage\",\n    \"user-resources\": \"customizing/user-resources\",\n    \"user-management\": \"customizing/user-management\",\n    \"user-environment\": \"customizing/user-environment\",\n    \"index-customization-guide\": \"jupyterhub/customization\",\n    \"extending-jupyterhub\": \"customizing/extending-jupyterhub\",\n    \"users-list\": \"community/users-list\",\n    \"tips\": \"community/tips\",\n    \"index-community-resources\": \"resources/community\",\n    \"additional-resources\": \"resources/community\",\n    \"upgrading\": \"administrator/upgrading\",\n    \"troubleshooting\": \"administrator/troubleshooting\",\n    \"security\": \"administrator/security\",\n    \"optimization\": \"administrator/optimization\",\n    \"index-administrator-guide\": \"administrator/index\",\n    \"debug\": \"administrator/debug\",\n    \"cost\": \"administrator/cost\",\n    \"authentication\": \"administrator/authentication\",\n    \"architecture\": \"administrator/architecture\",\n    \"advanced\": \"administrator/advanced\",\n}\n\n# opengraph configuration\n# ogp_site_url/prefix is set automatically by RTD\nogp_image = \"_static/logo.png\"\nogp_use_first_image = True\n\n# -- Generate the Helm chart configuration reference from a schema file ------\n\n# header\nwith open(\"resources/reference.txt\") as f:\n    header_md = f.readlines()\nheader_md = header_md[1:]\nheader_md = [ln.strip(\"\\n\") for ln in header_md]\n\n# schema\nwith open(\"../../jupyterhub/schema.yaml\") as f:\n    data = yaml.safe_load(f)\n\n\ndef parse_schema(d, md=[], depth=0, pre=\"\"):\n    \"\"\"\n    Generate markdown headers from a passed python dictionary created by\n    parsing a schema.yaml file.\n    \"\"\"\n    if \"then\" in d:\n        d = d[\"then\"]\n\n    if \"properties\" in d:\n        depth += 1\n        # Create markdown headers for each schema level\n        for key, val in d[\"properties\"].items():\n            md.append(f\"(schema_{pre}{key})=\")\n            md.append(\"#\" * (depth + 1) + f\" {pre}{key}\")\n            md.append(\"\")\n            if \"description\" in val:\n                for ln in val[\"description\"].split(\"\\n\"):\n                    md.append(ln)\n                md.append(\"\")\n\n            parse_schema(val, md, depth, f\"{pre}{key}.\")\n        depth -= 1\n    return md\n\n\nschema_md = parse_schema(data)\n\n# reference = header + schema\nreference_md = header_md + schema_md\nwith open(\"resources/reference.md\", \"w\") as f:\n    f.write(\"\\n\".join(reference_md))\n\n\n# -- Options for linkcheck builder -------------------------------------------\n# ref: http://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-the-linkcheck-builder\nlinkcheck_ignore = [\n    r\"(.*)github\\.com(.*)#\",  # javascript based anchors\n    r\"(.*)/#%21(.*)/(.*)\",  # /#!forum/jupyter - encoded anchor edge case\n    \"https://your-domain.com\",  # example\n    \"https://your-domain-name.com\",  # example\n    \"https://kubernetes.io/docs/tutorials/kubernetes-basics/\",  # works\n    \"https://cloud.ibm.com/kubernetes/catalog/create\",  # works\n    \"https://portal.azure.com\",  # sign-in redirect noise\n    \"https://console.cloud.google.com\",  # sign-in redirect noise\n    \"https://console.developers.google.com\",  # sign-in redirect noise\n]\nlinkcheck_anchors_ignore = [\n    \"/#!\",\n    \"/#%21\",\n]\n\n\n# -- Options for HTML output -------------------------------------------------\n# ref: http://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output\n\n# The theme to use for HTML and HTML Help pages.  See the documentation for\n# a list of builtin themes.\n#\n\nhtml_theme = \"pydata_sphinx_theme\"\nhtml_theme_options = {\n    \"github_url\": \"https://github.com/jupyterhub/zero-to-jupyterhub-k8s/\",\n    \"use_edit_page_button\": True,\n}\nhtml_context = {\n    \"github_user\": \"jupyterhub\",\n    \"github_repo\": \"zero-to-jupyterhub-k8s\",\n    \"github_version\": \"main\",\n    \"doc_path\": \"docs/source\",\n}\n\nhtml_favicon = \"_static/images/logo/favicon.ico\"\nhtml_logo = \"_static/images/logo/logo.png\"\n\n# Add any paths that contain custom static files (such as style sheets) here,\n# relative to this directory. They are copied after the builtin static files,\n# so a file named \"default.css\" will overwrite the builtin \"default.css\".\nhtml_static_path = [\"_static\"]\n", "path": "docs/source/conf.py"}], "after_files": [{"content": "# Configuration file for Sphinx to build our documentation to HTML.\n#\n# Configuration reference: https://www.sphinx-doc.org/en/master/usage/configuration.html\n#\n\n# -- Path setup --------------------------------------------------------------\n\n# If extensions (or modules to document with autodoc) are in another directory,\n# add these directories to sys.path here. If the directory is relative to the\n# documentation root, use os.path.abspath to make it absolute, like shown here.\n#\n# import os\n# import sys\n# sys.path.insert(0, os.path.abspath('.'))\n\n\n# -- Project specific imports ------------------------------------------------\n\nimport datetime\nimport os\nimport re\nimport subprocess\n\nimport yaml\n\n# -- Sphinx setup function ---------------------------------------------------\n# ref: http://www.sphinx-doc.org/en/latest/extdev/tutorial.html#the-setup-function\n\n\ndef setup(app):\n    app.add_css_file(\"custom.css\")\n\n\n# -- Referencable variables --------------------------------------------------\n\n\ndef _get_git_ref_from_chartpress_based_version(version):\n    \"\"\"\n    Get a git ref from a chartpress set version of format like\n    1.2.3-beta.1.n123.h1234567, 1.2.3-n123.h1234567, or 1.2.3.\n    \"\"\"\n    tag_hash_split = re.split(r\"[\\.|-]n\\d\\d\\d\\.h\", version)\n    if len(tag_hash_split) == 2:\n        return tag_hash_split[1]\n    else:\n        return tag_hash_split[0]\n\n\n# FIXME: Stop relying on chartpress to modify Chart.yaml (and values.yaml) by\n#        creating a new feature of chartpress that allows us to directly acquire\n#        the dynamically set chart version from Chart.yaml. This would be\n#        similar to the --list-images feature of chartpress.\nsubprocess.run([\"chartpress\", \"--skip-build\"], cwd=os.path.abspath(\"../..\"))\nwith open(\"../../jupyterhub/Chart.yaml\") as f:\n    chart = yaml.safe_load(f)\nsubprocess.run([\"chartpress\", \"--reset\"], cwd=os.path.abspath(\"../..\"))\n\n# These substitution variables only work in markdown contexts, and does not work\n# within links etc. Reference using {{ variable_name }}\n#\n# myst_substitutions ref: https://myst-parser.readthedocs.io/en/latest/using/syntax-optional.html#substitutions-with-jinja2\nmyst_substitutions = {\n    \"chart_version\": chart[\"version\"],\n    \"jupyterhub_version\": chart[\"appVersion\"],\n    # FIXME: kubeVersion contain >=, but by having > in the string we substitute\n    #        we run into this issue:\n    #        https://github.com/executablebooks/MyST-Parser/issues/282\n    \"kube_version\": chart[\"kubeVersion\"].split(\"-\", 1)[0][2:],\n    \"helm_version\": \"3.5\",\n    \"requirements\": f\"[hub/images/requirements.txt](https://github.com/jupyterhub/zero-to-jupyterhub-k8s/blob/{_get_git_ref_from_chartpress_based_version(chart['version'])}/images/hub/requirements.txt)\",\n}\n\n\n# -- General MyST configuration -----------------------------------------------------\n\n# myst_enable_extensions ref: https://myst-parser.readthedocs.io/en/latest/using/syntax-optional.html\nmyst_enable_extensions = [\n    \"substitution\",\n]\n\n\n# -- Project information -----------------------------------------------------\n# ref: https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information\n\nproject = \"Zero to JupyterHub with Kubernetes\"\ncopyright = f\"{datetime.date.today().year}, Project Jupyter Contributors\"\nauthor = \"Project Jupyter Contributors\"\n\n\n# -- General Sphinx configuration ---------------------------------------------------\n# ref: https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration\n\n# Set the default role so we can use `foo` instead of ``foo``\ndefault_role = \"literal\"\n\n# Add any Sphinx extension module names here, as strings. They can be\n# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom\n# ones.\nextensions = [\n    \"sphinx.ext.mathjax\",\n    \"sphinx_copybutton\",\n    \"myst_parser\",\n    \"sphinxext.rediraffe\",\n    \"sphinxext.opengraph\",\n]\n\n# List of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\n# This pattern also affects html_static_path and html_extra_path.\nexclude_patterns = []\n\n# The root toctree document.\nroot_doc = master_doc = \"index\"\n\n# The suffix(es) of source filenames.\nsource_suffix = [\".md\", \".rst\"]\n\n# Rediraffe redirects to ensure proper redirection\nrediraffe_redirects = {\n    \"customizing/user-management\": \"jupyterhub/customizing/user-management\",\n    \"customizing/user-storage\": \"jupyterhub/customizing/user-storage\",\n    \"customizing/user-resources\": \"jupyterhub/customizing/user-resources\",\n    \"customizing/user-environment\": \"jupyterhub/customizing/user-environment\",\n    \"customizing/extending-jupyterhub\": \"jupyterhub/customizing/extending-jupyterhub\",\n    \"reference/glossary\": \"resources/glossary\",\n    \"reference/tools\": \"resources/tools\",\n    \"reference/reference-docs\": \"resources/reference-docs\",\n    \"reference/reference\": \"resources/reference\",\n    \"community/additional-resources\": \"resources/community\",\n    \"community/users-list\": \"resources/community\",\n    \"community/tips\": \"resources/community\",\n    \"setup-jupyterhub/turn-off\": \"jupyterhub/uninstall\",\n    \"setup-jupyterhub/setup-jupyterhub\": \"jupyterhub/installation\",\n    \"setup-jupyterhub/setup-helm\": \"kubernetes/setup-helm\",\n    \"ovh/step-zero-ovh\": \"kubernetes/ovh/step-zero-ovh\",\n    \"digital-ocean/step-zero-digital-ocean\": \"kubernetes/digital-ocean/step-zero-digital-ocean\",\n    \"ibm/step-zero-ibm\": \"kubernetes/ibm/step-zero-ibm\",\n    \"redhat/step-zero-openshift\": \"kubernetes/redhat/step-zero-openshift\",\n    \"amazon/step-zero-aws-eks\": \"kubernetes/amazon/step-zero-aws-eks\",\n    \"amazon/step-zero-aws\": \"kubernetes/amazon/step-zero-aws\",\n    \"microsoft/step-zero-azure-autoscale\": \"kubernetes/microsoft/step-zero-azure-autoscale\",\n    \"microsoft/step-zero-azure\": \"kubernetes/microsoft/step-zero-azure\",\n    \"google/step-zero-gcp\": \"kubernetes/google/step-zero-gcp\",\n    \"create-k8s-cluster\": \"kubernetes/setup-kubernetes\",\n    \"turn-off\": \"jupyterhub/uninstall\",\n    \"setup-jupyterhub\": \"jupyterhub/index\",\n    \"setup-helm\": \"kubernetes/setup-helm\",\n    \"index-setup-jupyterhub\": \"jupyterhub/index\",\n    \"tools\": \"reference/tools\",\n    \"reference-docs\": \"reference/reference-docs\",\n    \"index-reference\": \"resources/reference\",\n    \"glossary\": \"reference/glossary\",\n    \"user-storage\": \"customizing/user-storage\",\n    \"user-resources\": \"customizing/user-resources\",\n    \"user-management\": \"customizing/user-management\",\n    \"user-environment\": \"customizing/user-environment\",\n    \"index-customization-guide\": \"jupyterhub/customization\",\n    \"extending-jupyterhub\": \"customizing/extending-jupyterhub\",\n    \"users-list\": \"community/users-list\",\n    \"tips\": \"community/tips\",\n    \"index-community-resources\": \"resources/community\",\n    \"additional-resources\": \"resources/community\",\n    \"upgrading\": \"administrator/upgrading\",\n    \"troubleshooting\": \"administrator/troubleshooting\",\n    \"security\": \"administrator/security\",\n    \"optimization\": \"administrator/optimization\",\n    \"index-administrator-guide\": \"administrator/index\",\n    \"debug\": \"administrator/debug\",\n    \"cost\": \"administrator/cost\",\n    \"authentication\": \"administrator/authentication\",\n    \"architecture\": \"administrator/architecture\",\n    \"advanced\": \"administrator/advanced\",\n}\n\n# opengraph configuration\n# ogp_site_url/prefix is set automatically by RTD\nogp_image = \"_static/logo.png\"\nogp_use_first_image = True\n\n# -- Generate the Helm chart configuration reference from a schema file ------\n\n# header\nwith open(\"resources/reference.txt\") as f:\n    header_md = f.readlines()\nheader_md = header_md[1:]\nheader_md = [ln.strip(\"\\n\") for ln in header_md]\n\n# schema\nwith open(\"../../jupyterhub/schema.yaml\") as f:\n    data = yaml.safe_load(f)\n\n\ndef parse_schema(d, md=[], depth=0, pre=\"\"):\n    \"\"\"\n    Generate markdown headers from a passed python dictionary created by\n    parsing a schema.yaml file.\n    \"\"\"\n    if \"then\" in d:\n        d = d[\"then\"]\n\n    if \"properties\" in d:\n        depth += 1\n        # Create markdown headers for each schema level\n        for key, val in d[\"properties\"].items():\n            md.append(f\"(schema_{pre}{key})=\")\n            md.append(\"#\" * (depth + 1) + f\" {pre}{key}\")\n            md.append(\"\")\n            if \"description\" in val:\n                for ln in val[\"description\"].split(\"\\n\"):\n                    md.append(ln)\n                md.append(\"\")\n\n            parse_schema(val, md, depth, f\"{pre}{key}.\")\n        depth -= 1\n    return md\n\n\nschema_md = parse_schema(data)\n\n# reference = header + schema\nreference_md = header_md + schema_md\nwith open(\"resources/reference.md\", \"w\") as f:\n    f.write(\"\\n\".join(reference_md))\n\n\n# -- Options for linkcheck builder -------------------------------------------\n# ref: http://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-the-linkcheck-builder\nlinkcheck_ignore = [\n    r\"(.*)github\\.com(.*)#\",  # javascript based anchors\n    r\"(.*)/#%21(.*)/(.*)\",  # /#!forum/jupyter - encoded anchor edge case\n    r\"https://github.com/[^/]*$\",  # too many github usernames / searches in changelog\n    \"https://github.com/jupyterhub/zero-to-jupyterhub-k8s/pull/\",  # too many PRs in changelog\n    \"https://github.com/jupyterhub/zero-to-jupyterhub-k8s/compare/\",  # too many comparisons in changelog\n    \"https://your-domain.com\",  # example\n    \"https://your-domain-name.com\",  # example\n    \"https://kubernetes.io/docs/tutorials/kubernetes-basics/\",  # works\n    \"https://cloud.ibm.com/kubernetes/catalog/create\",  # works\n    \"https://portal.azure.com\",  # sign-in redirect noise\n    \"https://console.cloud.google.com\",  # sign-in redirect noise\n    \"https://console.developers.google.com\",  # sign-in redirect noise\n]\nlinkcheck_anchors_ignore = [\n    \"/#!\",\n    \"/#%21\",\n]\n\n\n# -- Options for HTML output -------------------------------------------------\n# ref: http://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output\n\n# The theme to use for HTML and HTML Help pages.  See the documentation for\n# a list of builtin themes.\n#\n\nhtml_theme = \"pydata_sphinx_theme\"\nhtml_theme_options = {\n    \"github_url\": \"https://github.com/jupyterhub/zero-to-jupyterhub-k8s/\",\n    \"use_edit_page_button\": True,\n}\nhtml_context = {\n    \"github_user\": \"jupyterhub\",\n    \"github_repo\": \"zero-to-jupyterhub-k8s\",\n    \"github_version\": \"main\",\n    \"doc_path\": \"docs/source\",\n}\n\nhtml_favicon = \"_static/images/logo/favicon.ico\"\nhtml_logo = \"_static/images/logo/logo.png\"\n\n# Add any paths that contain custom static files (such as style sheets) here,\n# relative to this directory. They are copied after the builtin static files,\n# so a file named \"default.css\" will overwrite the builtin \"default.css\".\nhtml_static_path = [\"_static\"]\n", "path": "docs/source/conf.py"}]}