Skip to content

Commit 1d32da6

Browse files
authored
Merge pull request #8190 from readthedocs/humitos/design-doc-future-builder
Design doc: forward path to a future builder
2 parents bae84f6 + d064b12 commit 1d32da6

File tree

1 file changed

+261
-0
lines changed

1 file changed

+261
-0
lines changed

docs/dev/design/future-builder.rst

+261
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
Future Builder
2+
==============
3+
4+
.. contents::
5+
:local:
6+
:depth: 2
7+
8+
This document is a continuation of Santos' work about "`Explicit Builders`_".
9+
It builds on top of that document some extra features and makes some decisions about the final goal,
10+
proposing a clear direction to move forward with intermediate steps keeping backward and forward compatibility.
11+
12+
.. _Explicit Builders: https://github.com/readthedocs/readthedocs.org/pull/8103/
13+
14+
.. note::
15+
16+
A lot of things have changed since this document was written.
17+
We have had multiple discussions where we already took some decisions and discarded some of the ideas/details proposed here.
18+
The document was merged as-is without a cleaned up and there could be some inconsistencies.
19+
Note that ``build.jobs`` and ``build.commands`` are already implemented *without definig a contract* yet,
20+
and with small differences from the idea described here.
21+
22+
Please, refer to the following links to read more about all the discussions we already had:
23+
24+
- Public discussions:
25+
26+
- https://github.com/readthedocs/readthedocs.org/issues/9062
27+
- https://github.com/readthedocs/readthedocs.org/issues/1083
28+
- https://github.com/readthedocs/readthedocs.org/issues/9063
29+
- https://github.com/readthedocs/readthedocs.org/issues/9088
30+
31+
- Private discussions:
32+
33+
- https://github.com/readthedocs/meta/discussions/9
34+
- https://github.com/readthedocs/meta/discussions/14
35+
- https://github.com/readthedocs/meta/discussions/17
36+
37+
38+
39+
Goals
40+
-----
41+
42+
* Keep the current builder working as-is
43+
* Keep backward and forward (with intermediate steps) compatibility
44+
* Define a clear support for newbie, intermediate and advanced users
45+
* Allow users to override a command, run pre/post hook commands or define all commands by themselves
46+
* Remove the Read the Docs requirement of having access to the build process
47+
* Translate our current magic at build time to a defined contract with the user
48+
* Provide a way to add a command argument without implementing it as a config file (e.g. ``fail_on_warning``)
49+
* Define a path forward towards supporting other tools
50+
* Re-write all ``readthedocs-sphinx-ext`` features to post-processsing HTML features
51+
* Reduce complexity maintained by Read the Docs' core team
52+
* Make Read the Docs responsible for Sphinx support and delegate other tools to the community
53+
* Eventually support upload pre-build docs
54+
* Allow us to add a feature with a defined contract without worry about breaking old builds
55+
* Introduce ``build.builder: 2`` config (does not install pre-defined packages) for these new features
56+
* Motivate users to migrate to ``v2`` to finally deprecate this magic by educating users
57+
58+
59+
Steps ran by the builder
60+
------------------------
61+
62+
Read the Docs currently controls all the build process.
63+
Users are only allowed to modify very limited behavior by using a ``.readthedocs.yaml`` file.
64+
This drove us to implement features like ``sphinx.fail_on_warning``, ``submodules``, among others,
65+
at a high implementation and maintenance cost to the core team.
66+
Besides, this hasn't been enough for more advanced users that require more control over these commands.
67+
68+
This document proposes to clearly define the steps the builder ran and allow users to override them
69+
depending on their needings:
70+
71+
- Newbie user / simple platform usage: Read the Docs controls all the commands (current builder)
72+
- Intermediate user: ability to override one or more commands plus running pre/post hooks
73+
- Advanced user: controls *all the commands* executed by the builder
74+
75+
The steps identified so far are:
76+
77+
#. Checkout
78+
#. Expose project data via environment variables (\*)
79+
#. Create environment (virtualenv / conda)
80+
#. Install dependencies
81+
#. Build documentation
82+
#. Generate defined contract (``metadata.yaml``)
83+
#. Post-process HTML (\*)
84+
#. Upload to storage (\*)
85+
86+
Steps marked with *(\*)* are managed by Read the Docs and can't be overwritten.
87+
88+
89+
Defined contract
90+
----------------
91+
92+
Projects building on Read the Docs must provide a ``metadata.yaml`` file after running their last command.
93+
This file contains all the data required by Read the Docs to be able to add its integrations.
94+
If this file is not provided or malformed, Read the Docs will fail the build and stop the process
95+
communicating to the user that there was a problem with the ``metadata.yaml`` and we require them to fix the problem.
96+
97+
.. note::
98+
99+
There is no restriction about how this file is generated
100+
(e.g. generated with Python, Bash, statically uploaded to the repository, etc)
101+
Read the Docs does not have control over it and it's only responsible for generating it when building with Sphinx.
102+
103+
104+
The following is an example of a ``metadata.yaml`` that is generated by Read the Docs when building Sphinx documentation:
105+
106+
.. code:: yaml
107+
108+
# metadata.yaml
109+
version: 1
110+
tool:
111+
name: sphinx
112+
version: 3.5.1
113+
builder: html
114+
readthedocs:
115+
html_output: ./_build/html/
116+
pdf_output: ./_build/pdf/myproject.pdf
117+
epub_output: ./_build/pdf/myproject.epub
118+
search:
119+
enabled: true
120+
css_identifier: #search-form > input[name="q"]
121+
analytics: false
122+
flyout: false
123+
canonical: docs.myproject.com
124+
language: en
125+
126+
.. warning::
127+
128+
The ``metadata.yaml`` contract is not defined yet.
129+
This is just an example of what we could expect from it to be able to add our integrations.
130+
131+
132+
Config file
133+
-----------
134+
135+
As we mentioned, we want all users to use the same config file and have a clear way to override commands as they need.
136+
This will be done by using the current ``.readthedocs.yaml`` file that we already have by adding two new keys:
137+
``build.jobs`` and ``build.commands``.
138+
139+
If neither ``build.jobs`` or ``build.commands`` are present in the config file,
140+
Read the Docs will execute the builder we currently support without modification,
141+
keeping compatibility with all projects already building successfully.
142+
143+
When users make usage of ``jobs:`` or ``commands:`` keys we are not responsible for them in case they fail.
144+
In these cases, we only check for a ``metadata.yaml`` file and run our code to add the integrations.
145+
146+
147+
``build.jobs``
148+
~~~~~~~~~~~~~~
149+
150+
It allows users to execute one or multiple pre/post hooks and/or overwrite one or multiple commands.
151+
These are some examples where this is useful:
152+
153+
- User wants to pass an extra argument to ``sphinx-build``
154+
- Project requires to execute a command *before* building
155+
- User has a personal/private PyPI URL
156+
- Install project with `pip install -e` (see https://github.com/readthedocs/readthedocs.org/issues/6243)
157+
- Disable git shallow clone (see https://github.com/readthedocs/readthedocs.org/issues/5989)
158+
- Call `pip install` with `--constraint` (see https://github.com/readthedocs/readthedocs.org/issues/7258)
159+
- Do something _before_ install (see https://github.com/readthedocs/readthedocs.org/issues/6662)
160+
- Use a conda lock file to create the environment (see https://github.com/readthedocs/readthedocs.org/issues/7772)
161+
- Run a check after the build is done (e.g. ``sphinx-build -W -b linkcheck . _build/html``)
162+
- Create virtualenv with ``--system-site-packages``
163+
- etc
164+
165+
.. code:: yaml
166+
167+
# .readthedocs.yaml
168+
build:
169+
builder: 2
170+
jobs:
171+
pre_checkout:
172+
checkout: git clone --branch main https://github.com/readthedocs/readthedocs.org
173+
post_checkout:
174+
pre_create_environment:
175+
create_environment: python -m virtualenv venv
176+
post_create_environment:
177+
pre_install:
178+
install: pip install -r requirements.txt
179+
post_install:
180+
pre_build:
181+
build:
182+
html: sphinx-build -T -j auto -E -b html -d _build/doctrees -D language=en . _build/html
183+
pdf: latexmk -r latexmkrc -pdf -f -dvi- -ps- -jobname=test-builds -interaction=nonstopmode
184+
epub: sphinx -T -j auto -b epub -d _build/doctrees -D language=en . _build/epub
185+
post_build:
186+
pre_metadata:
187+
metadata: ./metadata_sphinx.py
188+
post_medatada:
189+
190+
191+
.. note::
192+
193+
*All these commands* are executed passing all the exposed environment variables.
194+
195+
If the user only provides a subset of these jobs, we ran our default commands if the user does not provide them
196+
(see :ref:`Step ran by the builder`).
197+
For example, the following YAML is enough when the project requires running Doxygen as a pre-build step:
198+
199+
.. code:: yaml
200+
201+
# .readthedocs.yaml
202+
build:
203+
builder: 2
204+
jobs:
205+
# https://breathe.readthedocs.io/en/latest/readthedocs.html#generating-doxygen-xml-files
206+
pre_build: cd ../doxygen; doxygen
207+
208+
209+
``build.commands``
210+
~~~~~~~~~~~~~~~~~~
211+
212+
It allows users to have full control over the commands executed in the build process.
213+
These are some examples where this is useful:
214+
215+
- project with a custom build process that does map ours
216+
- specific requirements that we can't/want to cover as a general rule
217+
- build documentation with a different tool than Sphinx
218+
219+
220+
.. code:: yaml
221+
222+
# .readthedocs.yaml
223+
build:
224+
builder: 2
225+
commands:
226+
- git clone --branch main https://github.com/readthedocs/readthedocs.org
227+
- pip install -r requirements.txt
228+
- sphinx-build -T -j auto -E -b html -d _build/doctrees -D language=en . _build/html
229+
- ./metadata.py
230+
231+
232+
Intermediate steps for rollout
233+
------------------------------
234+
235+
#. Remove all the exposed data in the ``conf.py.tmpl`` file and move it to ``metadata.yaml``
236+
#. Define structure required for ``metadata.yaml`` as contract
237+
#. Define the environment variables required (e.g. some from ``html_context``) and execute all commands with them
238+
#. Build documentation using this contract
239+
#. Leave ``readthedocs-sphinx-ext`` as the only package installed and extension install in ``conf.py.tmpl``
240+
#. Add ``build.builder: 2`` config without any *magic*
241+
#. Build everything needed to support ``build.jobs`` and ``build.commands`` keys
242+
#. Write guides about how to use the new keys
243+
#. Re-write ``readthedocs-sphinx-ext`` features to post-process HTML features
244+
245+
246+
Final notes
247+
-----------
248+
249+
- The migration path from ``v1`` to ``v2`` will require users to explicitly specify their requirements
250+
(we don't install pre-defined packages anymore)
251+
- We probably not want to support ``build.jobs`` on ``v1`` to reduce core team's time maintaining that code
252+
without the ability to update it due to projects randomly breaking.
253+
- We would be able to start building documentation using new tools without having to *integrate them*.
254+
- Building on Read the Docs with a new tool will require:
255+
- the user to execute a different set of commands by overriding the defaults.
256+
- the project/build/user to expose a ``metadata.yaml`` with the contract that Read the Docs expects.
257+
- none, some or all the integrations will be added to the HTML output (these have to be implemented at Read the Docs core)
258+
- We are not responsible for extra formats (e.g. PDF, ePub, etc) on other tools.
259+
- Focus on support Sphinx with nice integrations made in a tool-agnostic way that can be re-used.
260+
- Removing the manipulation of ``conf.py.tmpl`` does not require us to implement the same manipulation
261+
for projects using the new potential feature ``sphinx.yaml`` file.

0 commit comments

Comments
 (0)