From 385443081df51fbde28f0fd98cab7e2716af9f6d Mon Sep 17 00:00:00 2001 From: Andreas Zwinkau Date: Thu, 23 Apr 2026 10:13:58 +0200 Subject: [PATCH 1/8] draft DR-008-infra --- docs/design_decisions/DR-008-infra.rst | 148 +++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 docs/design_decisions/DR-008-infra.rst diff --git a/docs/design_decisions/DR-008-infra.rst b/docs/design_decisions/DR-008-infra.rst new file mode 100644 index 00000000000..746aa363425 --- /dev/null +++ b/docs/design_decisions/DR-008-infra.rst @@ -0,0 +1,148 @@ +.. + Copyright (c) 2026 Contributors to the Eclipse Foundation + + See the NOTICE file(s) distributed with this work for additional + information regarding copyright ownership. + + This program and the accompanying materials are made available under the + terms of the Apache License Version 2.0 which is available at + https://www.apache.org/licenses/LICENSE-2.0 + + SPDX-License-Identifier: Apache-2.0 + +DR-008-Infra: Generating documentation sources via Bazel +======================================================== + +- **Date:** 2026-04-23 + +.. dec_rec:: Generating documentation sources via Bazel + :id: dec_rec__infra__docs_src_dir + :status: proposed + :context: Infrastructure + :decision: Option B because Option B loses wrt flexibility + +Context / Problem +----------------- + +The docs-as-code system builds documentation by reading from a static ``source_dir`` (default ``"docs/"``) on the workspace filesystem. +Three build paths coexist: + +1. **Live preview** — Local development via `sphinx-autobuild `_. +2. **Direct Sphinx** — Sphinx invoked in the same venv for fast iteration or CI. +3. **Bazel sandbox** — ``needs_json`` and similar targets run Sphinx in a hermetic sandbox. + +We have no generic solution for generating parts of the documentation source directory via Bazel. +See `docs-as-code issue #423 `_ for an open feature request +to implement "Extra docs pages from artifacts". + +Workarounds we already have in place are: + +* Use ``.`` as source directory to place sources anywhere. + This implies a careful maintenance of include/exclude patterns in ``conf.py``. +* Generate json files for special inputs like source links or test reports. + This is limiting because we cannot generate whole pages or directories with this approach. +* The ``:docs_combo`` does compose a sources directory via `sphinx-collections `_. + It allows no control over the folder hierarchy + and symlinks in the git workspace can be confusing. + +We look for a solution which is simpler and easier to maintain. + +Additionally, we repeatedly has issues with caching. +Since we don't rely on Bazel sandbox for docs building, Bazel cannot help with hermeticity and determinism. +We need incremental builds locally and determinism with caching in CI. +See `rules_python sphinxdocs `_ +how an idea how to achieve this using Bazel. + +The "Module API" proposal +(somewhat implemented in `tooling PR 95 `_) +fully relies on Bazel. +It is not compatible with the docs-as-code live preview as of now. + +Goals +^^^^^ + +- **Effort**: Minimise one-time implementation and ongoing maintenance cost. +- **Flexibility**: Minimise the effort for potential future extensions. +- **Speed**: Minimise the build time for documentation builds, especially for live preview. +- ... + +Non-Goals +^^^^^^^^^ + +- Replacing Sphinx or Sphinx-Needs as documentation tools. +- Keep Esbonio language server alive as we assume nobody is using it. + +Options Considered +------------------ + +Option N: No change (status quo) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Keep the current architecture. +The ``docs()`` macro in ``docs.bzl`` accepts a ``source_dir`` parameter and reads +documentation sources directly from that directory on the workspace filesystem. + +.. mermaid:: + + graph LR + docs@{ shape: docs, label: "docs/" } + docs --> :docs + docs --> :live_preview + :live_preview -- watch --> docs + + +Effort 💚: No implementation work required. + +Flexibility 😡: More workarounds instead of generic solution. + +Speed 💚: Fast but only covers source updates (not test result updates, for example). + + +Option B: Introduce ``:docs_src_dir`` Bazel target +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Add a new ``:docs_src_dir`` target that composes the documentation source +directory inside Bazel using symlinks, generated files, and so on. + +.. mermaid:: + + graph LR + docs@{ shape: docs, label: "docs/" } + preview@{ shape: subproc, label: "live_preview" } + docs --> :docs_src_dir --> :docs --> preview + preview -- rebuild --> :docs + +The live preview is replaced by a custom implementation. +This live preview cannot be executed via ``bazel run`` because of the need to rebuild via Bazel internally. +Thus, there is no ``:live_preview`` target but a ``live_preview`` script. +We cannot rely on watching file system changes to trigger rebuilds because the source directory is composed by Bazel +and may contain generated files. + +Effort 😡: Significant implementation effort. + +Flexibility 💚: Generic solution for all build paths and future extensions. + +Speed: unclear + +Evaluation +---------- + +In order of importance, most important first. + +.. csv-table:: + :header: Goals, Option N, Option B + :widths: 2, 1, 1 + + Flexibility, 😡, 💚 + Effort, 💚, 😡 + Speed, 💚, ? + +**Decision:** Option B because Option N loses wrt flexibility + +Appendix: any_folder experiment +------------------------------- + +For a brief moment, we had an ``any_folder`` extension but removed it before the docs-as-code release. +It breaks when using such documentation in ``:docs_combo``: +It relied on configuration in ``conf.py`` but with ``:docs_combo`` +the modules' ``conf.py`` is ignored and only the root ``conf.py`` is used. From 329bafcfdb7707fc7f5246f560a7430bf27eea0d Mon Sep 17 00:00:00 2001 From: Andreas Zwinkau Date: Mon, 27 Apr 2026 17:37:42 +0200 Subject: [PATCH 2/8] Insights from experimenting --- docs/design_decisions/DR-008-infra.rst | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/design_decisions/DR-008-infra.rst b/docs/design_decisions/DR-008-infra.rst index 746aa363425..a640380e1da 100644 --- a/docs/design_decisions/DR-008-infra.rst +++ b/docs/design_decisions/DR-008-infra.rst @@ -104,6 +104,12 @@ Option B: Introduce ``:docs_src_dir`` Bazel target Add a new ``:docs_src_dir`` target that composes the documentation source directory inside Bazel using symlinks, generated files, and so on. +We can add an ``extra_docs`` attribute to the ``docs()`` macro which accepts a list of labels. +When extra_docs is non-empty, we create a `sphinx_docs_library `_ +target and pass it to ``:needs_json`` via deps. +sphinx_docs already knows how to merge deps entries into its source tree using each entry's strip_prefix/prefix metadata — no custom code needed. + + .. mermaid:: graph LR @@ -118,7 +124,12 @@ Thus, there is no ``:live_preview`` target but a ``live_preview`` script. We cannot rely on watching file system changes to trigger rebuilds because the source directory is composed by Bazel and may contain generated files. -Effort 😡: Significant implementation effort. +The ``score_sync_toml`` extension writes a ``ubproject.toml`` file to the source directory +but Bazel sandboxing makes this fail. +As a workaround, ``needscfg_outpath`` can be used to redirect it somewhere else. +Alternatively, ``remove score_sync_toml`` and ``needs_config_writer`` extensions and create the ubproject.toml file in a different way? + +Effort 😡: Some implementation effort. Flexibility 💚: Generic solution for all build paths and future extensions. From 07413883d5170dc1b89bbb3698407b2a3cbe042f Mon Sep 17 00:00:00 2001 From: Andreas Zwinkau Date: Thu, 30 Apr 2026 08:43:02 +0200 Subject: [PATCH 3/8] More experimenting --- docs/design_decisions/DR-008-infra.rst | 34 +++++++++++++++++--------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/docs/design_decisions/DR-008-infra.rst b/docs/design_decisions/DR-008-infra.rst index a640380e1da..6334ae2bc7e 100644 --- a/docs/design_decisions/DR-008-infra.rst +++ b/docs/design_decisions/DR-008-infra.rst @@ -19,7 +19,7 @@ DR-008-Infra: Generating documentation sources via Bazel :id: dec_rec__infra__docs_src_dir :status: proposed :context: Infrastructure - :decision: Option B because Option B loses wrt flexibility + :decision: Option B because Option N loses wrt flexibility Context / Problem ----------------- @@ -64,7 +64,7 @@ Goals - **Effort**: Minimise one-time implementation and ongoing maintenance cost. - **Flexibility**: Minimise the effort for potential future extensions. - **Speed**: Minimise the build time for documentation builds, especially for live preview. -- ... +- **UX**: Minimize efforts necessary to documentation work. Non-Goals ^^^^^^^^^ @@ -97,26 +97,28 @@ Flexibility 😡: More workarounds instead of generic solution. Speed 💚: Fast but only covers source updates (not test result updates, for example). +UX 💚: Status quo + Option B: Introduce ``:docs_src_dir`` Bazel target ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Add a new ``:docs_src_dir`` target that composes the documentation source -directory inside Bazel using symlinks, generated files, and so on. - -We can add an ``extra_docs`` attribute to the ``docs()`` macro which accepts a list of labels. -When extra_docs is non-empty, we create a `sphinx_docs_library `_ -target and pass it to ``:needs_json`` via deps. -sphinx_docs already knows how to merge deps entries into its source tree using each entry's strip_prefix/prefix metadata — no custom code needed. - +We add an ``extra_docs`` attribute to the ``docs()`` macro +for additional sources specified via `sphinx_docs_library `_, +which allows to adapt path prefixes. +The we materialize a composed folder for the actual sphinx-build. .. mermaid:: graph LR docs@{ shape: docs, label: "docs/" } + extradocs@{ shape: docs, label: "extra_srcs" } preview@{ shape: subproc, label: "live_preview" } - docs --> :docs_src_dir --> :docs --> preview + allsrc@{ label: ":docs_src_dir" } + docs --> allsrc --> :docs --> preview + extradocs --> allsrc preview -- rebuild --> :docs + allsrc --> :needs_json The live preview is replaced by a custom implementation. This live preview cannot be executed via ``bazel run`` because of the need to rebuild via Bazel internally. @@ -124,6 +126,10 @@ Thus, there is no ``:live_preview`` target but a ``live_preview`` script. We cannot rely on watching file system changes to trigger rebuilds because the source directory is composed by Bazel and may contain generated files. +For the implementation we can rely on `ibazel / bazel-watcher `_ +to trigger rebuilds of the ``:docs_src_dir`` target and then still use sphinx-autobuild for the browser auto-reload. +As a side-effect, ibazel is a new tool in S-CORE which could be reused for other auto-rebuild use cases like unit tests. + The ``score_sync_toml`` extension writes a ``ubproject.toml`` file to the source directory but Bazel sandboxing makes this fail. As a workaround, ``needscfg_outpath`` can be used to redirect it somewhere else. @@ -133,7 +139,10 @@ Effort 😡: Some implementation effort. Flexibility 💚: Generic solution for all build paths and future extensions. -Speed: unclear +Speed ?: unclear + +UX 😡: Live-preview requires a setup step to generate the script. + Evaluation ---------- @@ -147,6 +156,7 @@ In order of importance, most important first. Flexibility, 😡, 💚 Effort, 💚, 😡 Speed, 💚, ? + UX, 💚, 😡 **Decision:** Option B because Option N loses wrt flexibility From 5cd1ef9eae194c9efb82de818aee073d80ef05ef Mon Sep 17 00:00:00 2001 From: Andreas Zwinkau Date: Mon, 4 May 2026 09:16:00 +0200 Subject: [PATCH 4/8] Add option D --- docs/design_decisions/DR-008-infra.rst | 32 ++++++++++++++++++++------ 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/docs/design_decisions/DR-008-infra.rst b/docs/design_decisions/DR-008-infra.rst index 6334ae2bc7e..ff3d705d7ea 100644 --- a/docs/design_decisions/DR-008-infra.rst +++ b/docs/design_decisions/DR-008-infra.rst @@ -57,6 +57,8 @@ The "Module API" proposal (somewhat implemented in `tooling PR 95 `_) fully relies on Bazel. It is not compatible with the docs-as-code live preview as of now. +`Another exploration by Useblocks `_ +is available but does not cover live preview either. Goals ^^^^^ @@ -144,21 +146,37 @@ Speed ?: unclear UX 😡: Live-preview requires a setup step to generate the script. +Option D: Dual-path — keep ``:live_preview``, add hermetic ``:docs`` build +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Keep the existing ``bazel run :live_preview`` target unchanged (sphinx-autobuild watching ``docs/`` on the workspace filesystem). +In parallel, introduce a separate hermetic ``bazel build :docs`` target +that materialises a composed source directory inside the Bazel sandbox before invoking Sphinx. + +Effort 😡: By definition requires nearly the effort for option N and B combined. + +Flexibility 😡: Still requires all the workarounds of option N. + +Speed 💚: No slowdown. + +UX 😡: Live-preview UX is unchanged, but risk of downstream breaks. + + Evaluation ---------- In order of importance, most important first. .. csv-table:: - :header: Goals, Option N, Option B - :widths: 2, 1, 1 + :header: Goals, Option N, Option B, Option D + :widths: 2, 1, 1, 1 - Flexibility, 😡, 💚 - Effort, 💚, 😡 - Speed, 💚, ? - UX, 💚, 😡 + Flexibility, 😡, 💚, 😡 + Effort, 💚, 😡, 😡 + Speed, 💚, ?, 💚 + UX, 💚, 😡, 😡 -**Decision:** Option B because Option N loses wrt flexibility +**Decision: Option B** because Option N loses wrt flexibility. Option D has no advantage over B. Appendix: any_folder experiment ------------------------------- From 63873c09f50f863aa1dcc4741308f7ada680a43f Mon Sep 17 00:00:00 2001 From: Andreas Zwinkau Date: Mon, 11 May 2026 15:15:23 +0200 Subject: [PATCH 5/8] feat: more insights from experimenting --- docs/design_decisions/DR-008-infra.rst | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/docs/design_decisions/DR-008-infra.rst b/docs/design_decisions/DR-008-infra.rst index ff3d705d7ea..e66971034f5 100644 --- a/docs/design_decisions/DR-008-infra.rst +++ b/docs/design_decisions/DR-008-infra.rst @@ -13,7 +13,7 @@ DR-008-Infra: Generating documentation sources via Bazel ======================================================== -- **Date:** 2026-04-23 +- **Date:** 2026-05-11 .. dec_rec:: Generating documentation sources via Bazel :id: dec_rec__infra__docs_src_dir @@ -108,7 +108,9 @@ Option B: Introduce ``:docs_src_dir`` Bazel target We add an ``extra_docs`` attribute to the ``docs()`` macro for additional sources specified via `sphinx_docs_library `_, which allows to adapt path prefixes. -The we materialize a composed folder for the actual sphinx-build. +The source tree is materialized using hardlinks (``ln``) inside a Bazel ``declare_directory`` action. +Symlinks fail Bazel's output tree validation (dangling link detection), +while copies are unnecessarily expensive for large doc sets. .. mermaid:: @@ -128,22 +130,26 @@ Thus, there is no ``:live_preview`` target but a ``live_preview`` script. We cannot rely on watching file system changes to trigger rebuilds because the source directory is composed by Bazel and may contain generated files. -For the implementation we can rely on `ibazel / bazel-watcher `_ -to trigger rebuilds of the ``:docs_src_dir`` target and then still use sphinx-autobuild for the browser auto-reload. -As a side-effect, ibazel is a new tool in S-CORE which could be reused for other auto-rebuild use cases like unit tests. +The ``live_preview`` script runs two concurrent processes: + +1. ``ibazel build :docs_src_dir`` — watches workspace sources and re-materializes the tree on change. +2. ``sphinx-autobuild`` — watches the materialized tree and serves HTML with websocket-based browser reload. The ``score_sync_toml`` extension writes a ``ubproject.toml`` file to the source directory but Bazel sandboxing makes this fail. -As a workaround, ``needscfg_outpath`` can be used to redirect it somewhere else. -Alternatively, ``remove score_sync_toml`` and ``needs_config_writer`` extensions and create the ubproject.toml file in a different way? +The ``score_sync_toml`` extension's write to the source directory is redirected via +``--define=needscfg_outpath=/docs/ubproject.toml``, +which works without modifications to the extension itself. Effort 😡: Some implementation effort. Flexibility 💚: Generic solution for all build paths and future extensions. -Speed ?: unclear +Speed 💛: Overall latency is comparable to the status quo for edit-preview cycles, but the initial cold start is a little slower due to the extra Bazel invocation. -UX 😡: Live-preview requires a setup step to generate the script. +UX 😡: Requires a two-step setup: ``bazel run //:ide_support`` (venv) then +``bazel run //:gen_live_preview`` (script). +The generated script is workspace-specific and should be gitignored. Option D: Dual-path — keep ``:live_preview``, add hermetic ``:docs`` build @@ -173,7 +179,7 @@ In order of importance, most important first. Flexibility, 😡, 💚, 😡 Effort, 💚, 😡, 😡 - Speed, 💚, ?, 💚 + Speed, 💚, 💛, 💚 UX, 💚, 😡, 😡 **Decision: Option B** because Option N loses wrt flexibility. Option D has no advantage over B. From e75f4fdc3c1ad51447326ca9045719f56a1a8eb2 Mon Sep 17 00:00:00 2001 From: Andreas Zwinkau Date: Mon, 11 May 2026 15:32:43 +0200 Subject: [PATCH 6/8] chore: update evaluation --- docs/design_decisions/DR-008-infra.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/design_decisions/DR-008-infra.rst b/docs/design_decisions/DR-008-infra.rst index e66971034f5..ad2fefd0981 100644 --- a/docs/design_decisions/DR-008-infra.rst +++ b/docs/design_decisions/DR-008-infra.rst @@ -141,7 +141,7 @@ The ``score_sync_toml`` extension's write to the source directory is redirected ``--define=needscfg_outpath=/docs/ubproject.toml``, which works without modifications to the extension itself. -Effort 😡: Some implementation effort. +Effort 💛: Some implementation effort but prototype already works. Flexibility 💚: Generic solution for all build paths and future extensions. @@ -178,7 +178,7 @@ In order of importance, most important first. :widths: 2, 1, 1, 1 Flexibility, 😡, 💚, 😡 - Effort, 💚, 😡, 😡 + Effort, 💚, 💛, 😡 Speed, 💚, 💛, 💚 UX, 💚, 😡, 😡 From b753377a23fe6876ecab1431987fc94214ab0de2 Mon Sep 17 00:00:00 2001 From: Andreas Zwinkau Date: Wed, 13 May 2026 09:26:13 +0200 Subject: [PATCH 7/8] chore: address ChatGPT feedback --- docs/design_decisions/DR-008-infra.rst | 27 +++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/docs/design_decisions/DR-008-infra.rst b/docs/design_decisions/DR-008-infra.rst index ad2fefd0981..90a025720c4 100644 --- a/docs/design_decisions/DR-008-infra.rst +++ b/docs/design_decisions/DR-008-infra.rst @@ -13,11 +13,11 @@ DR-008-Infra: Generating documentation sources via Bazel ======================================================== -- **Date:** 2026-05-11 +- **Date:** 2026-05-13 .. dec_rec:: Generating documentation sources via Bazel :id: dec_rec__infra__docs_src_dir - :status: proposed + :status: accepted :context: Infrastructure :decision: Option B because Option N loses wrt flexibility @@ -45,7 +45,8 @@ Workarounds we already have in place are: It allows no control over the folder hierarchy and symlinks in the git workspace can be confusing. -We look for a solution which is simpler and easier to maintain. +We look for a solution which is simpler and easier to maintain, +so we don't have to keep adding more and more workarounds for each new use case. Additionally, we repeatedly has issues with caching. Since we don't rely on Bazel sandbox for docs building, Bazel cannot help with hermeticity and determinism. @@ -78,7 +79,7 @@ Options Considered ------------------ Option N: No change (status quo) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Keep the current architecture. The ``docs()`` macro in ``docs.bzl`` accepts a ``source_dir`` parameter and reads @@ -101,9 +102,16 @@ Speed 💚: Fast but only covers source updates (not test result updates, for ex UX 💚: Status quo +While ``sphinx-autobuild --pre-build`` is available to trigger some build steps before each rebuild, +this does not work with Bazel: +If you ``bazel run :live_preview`` and do a ``bazel build`` inside, +that build will wait for the run to finish, thus deadlock. Option B: Introduce ``:docs_src_dir`` Bazel target -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In short: sphinx-autobuild from a Bazel target that re-materializes the sources continuously via +`ibazel / bazel-watcher `_. We add an ``extra_docs`` attribute to the ``docs()`` macro for additional sources specified via `sphinx_docs_library `_, @@ -151,6 +159,15 @@ UX 😡: Requires a two-step setup: ``bazel run //:ide_support`` (venv) then ``bazel run //:gen_live_preview`` (script). The generated script is workspace-specific and should be gitignored. +The generally idea is also described in `the rules_python documentation `_: + +.. code-block:: bash + + bazel run //docs:docs.serve # Run in separate terminal + ibazel build //docs:docs # Automatically rebuilds docs + +This ``docs.serve`` target implemented in `rules_python` does not have +auto-refresh in the browser though. Option D: Dual-path — keep ``:live_preview``, add hermetic ``:docs`` build ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 7bd7dae2799b864fd7084ae32193dfc7f670799d Mon Sep 17 00:00:00 2001 From: Andreas Zwinkau Date: Mon, 18 May 2026 16:55:32 +0200 Subject: [PATCH 8/8] Update after infra meeting today --- docs/design_decisions/DR-008-infra.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/design_decisions/DR-008-infra.rst b/docs/design_decisions/DR-008-infra.rst index 90a025720c4..ea083aee0f3 100644 --- a/docs/design_decisions/DR-008-infra.rst +++ b/docs/design_decisions/DR-008-infra.rst @@ -13,7 +13,7 @@ DR-008-Infra: Generating documentation sources via Bazel ======================================================== -- **Date:** 2026-05-13 +- **Date:** 2026-05-18 .. dec_rec:: Generating documentation sources via Bazel :id: dec_rec__infra__docs_src_dir @@ -61,11 +61,14 @@ It is not compatible with the docs-as-code live preview as of now. `Another exploration by Useblocks `_ is available but does not cover live preview either. +We want dashboards generated automatically to be included in the documentation. +See `infrastructure discussion 2026-05-18 `_. + Goals ^^^^^ -- **Effort**: Minimise one-time implementation and ongoing maintenance cost. - **Flexibility**: Minimise the effort for potential future extensions. +- **Effort**: Minimise one-time implementation and ongoing maintenance cost. - **Speed**: Minimise the build time for documentation builds, especially for live preview. - **UX**: Minimize efforts necessary to documentation work.