Skip to content

Commit 6babe59

Browse files
authored
docs: tell how to setup readthedocs integration with sphinxdocs (bazel-contrib#2331)
This comes from setting up readthedocs integration with rules_testing. It'd be nice if so much copy/paste wasn't necessary, but I'm not sure how to best reduce that, so at the least, document what one has to do.
1 parent b4cc7b7 commit 6babe59

File tree

2 files changed

+157
-0
lines changed

2 files changed

+157
-0
lines changed

sphinxdocs/docs/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@ is agnostic as to what is being documented.
1717
1818
starlark-docgen
1919
sphinx-bzl
20+
readthedocs
2021
```

sphinxdocs/docs/readthedocs.md

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
:::{default-domain} bzl
2+
:::
3+
4+
# Read the Docs integration
5+
6+
The {obj}`readthedocs_install` rule provides support for making it easy
7+
to build for, and deploy to, Read the Docs. It does this by having Bazel do
8+
all the work of building, and then the outputs are copied to where Read the Docs
9+
expects served content to be placed. By having Bazel do the majority of work,
10+
you have more certainty that the docs you generate locally will match what
11+
is created in the Read the Docs build environment.
12+
13+
Setting this up is conceptually simple: make the Read the Docs build call `bazel
14+
run` with the appropriate args. To do this, it requires gluing a couple things
15+
together, most of which can be copy/pasted from the examples below.
16+
17+
## `.readthedocs.yaml` config
18+
19+
In order for Read the Docs to call our custom commands, we have to use the
20+
advanced `build.commands` setting of the config file. This needs to do two key
21+
things:
22+
1. Install Bazel
23+
2. Call `bazel run` with the appropriate args.
24+
25+
In the example below, `npm` is used to install Bazelisk and a helper shell
26+
script, `readthedocs_build.sh` is used to construct the Bazel invocation.
27+
28+
The key purpose of the shell script it to set the
29+
`--@rules_python//sphinxdocs:extra_env` and
30+
`--@rules_python//sphinxdocs:extra_defines` flags. These are used to communicate
31+
`READTHEDOCS*` environment variables and settings to the Bazel invocation.
32+
33+
## BUILD config
34+
35+
In your build file, the {obj}`readthedocs_install` rule handles building the
36+
docs and copying the output to the Read the Docs output directory
37+
(`$READTHEDOCS_OUTPUT` environment variable). As input, it takes a `sphinx_docs`
38+
target (the generated docs).
39+
40+
## conf.py config
41+
42+
Normally, readthedocs will inject extra content into your `conf.py` file
43+
to make certain integration available (e.g. the version selection flyout).
44+
However, because our yaml config uses the advanced `build.commands` feature,
45+
those config injections are disabled and we have to manually re-enable them.
46+
47+
To do this, we modify `conf.py` to detect `READTHEDOCS=True` in the environment
48+
and perform some additional logic. See the example code below for the
49+
modifications.
50+
51+
Depending on your theme, you may have to tweak the conf.py; the example is
52+
based on using the sphinx_rtd_theme.
53+
54+
## Example
55+
56+
```
57+
# File: .readthedocs.yaml
58+
version: 2
59+
60+
build:
61+
os: "ubuntu-22.04"
62+
tools:
63+
nodejs: "19"
64+
commands:
65+
- env
66+
- npm install -g @bazel/bazelisk
67+
- bazel version
68+
# Put the actual action behind a shell script because it's
69+
# easier to modify than the yaml config.
70+
- docs/readthedocs_build.sh
71+
```
72+
73+
```
74+
# File: docs/BUILD
75+
76+
load("@rules_python//sphinxdocs:readthedocs.bzl.bzl", "readthedocs_install")
77+
readthedocs_install(
78+
name = "readthedocs_install",
79+
docs = [":docs"],
80+
)
81+
```
82+
83+
```
84+
# File: docs/readthedocs_build.sh
85+
86+
#!/bin/bash
87+
88+
set -eou pipefail
89+
90+
declare -a extra_env
91+
while IFS='=' read -r -d '' name value; do
92+
if [[ "$name" == READTHEDOCS* ]]; then
93+
extra_env+=("--@rules_python//sphinxdocs:extra_env=$name=$value")
94+
fi
95+
done < <(env -0)
96+
97+
# In order to get the build number, we extract it from the host name
98+
extra_env+=("--@rules_python//sphinxdocs:extra_env=HOSTNAME=$HOSTNAME")
99+
100+
set -x
101+
bazel run \
102+
--stamp \
103+
"--@rules_python//sphinxdocs:extra_defines=version=$READTHEDOCS_VERSION" \
104+
"${extra_env[@]}" \
105+
//docs:readthedocs_install
106+
```
107+
108+
```
109+
# File: docs/conf.py
110+
111+
# Adapted from the template code:
112+
# https://github.com/readthedocs/readthedocs.org/blob/main/readthedocs/doc_builder/templates/doc_builder/conf.py.tmpl
113+
if os.environ.get("READTHEDOCS") == "True":
114+
# Must come first because it can interfere with other extensions, according
115+
# to the original conf.py template comments
116+
extensions.insert(0, "readthedocs_ext.readthedocs")
117+
118+
if os.environ.get("READTHEDOCS_VERSION_TYPE") == "external":
119+
# Insert after the main extension
120+
extensions.insert(1, "readthedocs_ext.external_version_warning")
121+
readthedocs_vcs_url = (
122+
"http://github.com/bazelbuild/rules_python/pull/{}".format(
123+
os.environ.get("READTHEDOCS_VERSION", "")
124+
)
125+
)
126+
# The build id isn't directly available, but it appears to be encoded
127+
# into the host name, so we can parse it from that. The format appears
128+
# to be `build-X-project-Y-Z`, where:
129+
# * X is an integer build id
130+
# * Y is an integer project id
131+
# * Z is the project name
132+
_build_id = os.environ.get("HOSTNAME", "build-0-project-0-rules-python")
133+
_build_id = _build_id.split("-")[1]
134+
readthedocs_build_url = (
135+
f"https://readthedocs.org/projects/rules-python/builds/{_build_id}"
136+
)
137+
138+
html_context = {
139+
# This controls whether the flyout menu is shown. It is always false
140+
# because:
141+
# * For local builds, the flyout menu is empty and doesn't show in the
142+
# same place as for RTD builds. No point in showing it locally.
143+
# * For RTD builds, the flyout menu is always automatically injected,
144+
# so having it be True makes the flyout show up twice.
145+
"READTHEDOCS": False,
146+
"github_version": os.environ.get("READTHEDOCS_GIT_IDENTIFIER", ""),
147+
# For local builds, the github link won't work. Disabling it replaces
148+
# it with a "view source" link to view the source Sphinx saw, which
149+
# is useful for local development.
150+
"display_github": os.environ.get("READTHEDOCS") == "True",
151+
"commit": os.environ.get("READTHEDOCS_GIT_COMMIT_HASH", "unknown commit"),
152+
# Used by readthedocs_ext.external_version_warning extension
153+
# This is the PR number being built
154+
"current_version": os.environ.get("READTHEDOCS_VERSION", ""),
155+
}
156+
```

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy