|
| 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