Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions docs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -503,12 +503,13 @@ def _sphinx_runtime_deps(deps):
result.append(fixed_dep)
return result

def _declare_docs_binary(name, srcs, data, deps, env, action):
def _declare_docs_binary(name, data, deps, env, action):
"""Declare one of the interactive documentation command targets."""
docs_cli_src = Label("//src/docs_cli:cli.py")
command_env = env | {"ACTION": action}
py_binary(
name = name,
srcs = srcs,
srcs = [docs_cli_src],
data = data,
deps = deps,
env = command_env,
Expand Down Expand Up @@ -632,7 +633,6 @@ def docs(
Label("//src/extensions/score_sphinx_bundle:score_sphinx_bundle"),
]

incremental_src = Label("//src:incremental.py")

known_good_label = [known_good] if known_good else []

Expand Down Expand Up @@ -706,7 +706,7 @@ def docs(
docs_env["SPHINX_CONFIG_FILE"] = "$(rlocationpath " + sphinx_config + ")"
if metamodel:
# The interactive ``py_binary`` targets run from a runfiles tree.
# incremental.py resolves this logical path through ``RUNFILES_DIR``.
# docs_cli resolves this logical path through ``RUNFILES_DIR``.
docs_env["SCORE_METAMODEL_YAML"] = "$(rlocationpath " + str(metamodel) + ")"
if known_good_label:
known_good_str = str(known_good_label[0])
Expand All @@ -718,7 +718,6 @@ def docs(
# ``docs``; expose this binary via the alias below instead.
_declare_docs_binary(
name = "_score_docs_cli",
srcs = [incremental_src],
data = docs_data,
deps = deps,
env = docs_env,
Expand All @@ -733,23 +732,20 @@ def docs(

_declare_docs_binary(
name = "docs_link_check",
srcs = [incremental_src],
data = docs_data,
deps = deps,
env = docs_env,
action = "linkcheck",
)
_declare_docs_binary(
name = "docs_check",
srcs = [incremental_src],
data = docs_data,
deps = deps,
env = docs_env,
action = "check",
)
_declare_docs_binary(
name = "live_preview",
srcs = [incremental_src],
data = docs_data,
deps = deps,
env = docs_env,
Expand Down
14 changes: 1 addition & 13 deletions src/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@
# *******************************************************************************

load("@aspect_rules_py//py:defs.bzl", "py_library")
load("@docs_as_code_hub_env//:requirements.bzl", "all_requirements")
load("@rules_java//java:java_binary.bzl", "java_binary")
load("@rules_python//python:pip.bzl", "compile_pip_requirements")
load("//:score_pytest.bzl", "score_pytest")

# These are only exported because they're passed as files to the //docs.bzl
# macros, and thus must be visible to other packages. They should only be
Expand All @@ -25,28 +23,18 @@ exports_files(
[
"requirements.txt",
"requirements.in",
"incremental.py",
"dummy.py",
"generate_sourcelinks_cli.py",
],
visibility = ["//visibility:public"],
)

score_pytest(
name = "incremental_dirty_build_test",
srcs = [
"incremental_dirty_build_test.py",
"incremental.py",
],
deps = all_requirements + ["//src/extensions/score_sphinx_bundle:score_sphinx_bundle"],
pytest_config = "//:pyproject.toml",
)

filegroup(
name = "all_sources",
srcs = glob(
["*.py"],
) + [
"//src/docs_cli:all_sources",
"//src/extensions/score_draw_uml_funcs:all_sources",
"//src/extensions/score_layout:all_sources",
"//src/extensions/score_metamodel:all_sources",
Expand Down
53 changes: 53 additions & 0 deletions src/docs_cli/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# *******************************************************************************
# 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
# *******************************************************************************

load("@docs_as_code_hub_env//:requirements.bzl", "all_requirements")
load("//:score_pytest.bzl", "score_pytest")

# docs.bzl passes this entry script as the source of each interactive binary.
# Exporting it allows docs() to declare those binaries in consumer packages.
exports_files(
["cli.py"],
visibility = ["//visibility:public"],
)

# The parent source collection must cross this Bazel package boundary
# explicitly so source-code linking continues to include the CLI and tests.
filegroup(
name = "all_sources",
srcs = glob(["*.py"]),
visibility = ["//visibility:public"],
)

score_pytest(
name = "dirty_build_test",
srcs = ["dirty_build_test.py", "cli.py"],
deps = all_requirements + [
"//src/extensions/score_mounts",
"//src/helper_lib",
],
pytest_config = "//:pyproject.toml",
)

# Exercise dispatch and the docs.bzl environment contract with the same
# entry script used by the interactive binaries. Its cli.py name also keeps
# it distinct from score_pytest's own main.py entry in the test sources.
score_pytest(
name = "main_test",
srcs = ["main_test.py", "cli.py"],
deps = all_requirements + [
"//src/extensions/score_mounts",
"//src/helper_lib",
],
pytest_config = "//:pyproject.toml",
)
78 changes: 78 additions & 0 deletions src/docs_cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<!--
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
-->

# Documentation CLI

This package runs local documentation builds and live preview for the targets
created by [`docs()`](../../../docs.bzl). Bazel supplies the source files,
configuration, dependencies and environment for each invocation.

## Commands

Run these targets in the package that calls `docs()`. The examples assume the
workspace root; for a nested package, use a label such as `//component:docs`.

| Command | Action | Result |
| --- | --- | --- |
| `bazel run //:docs` | `incremental` | Build HTML, reusing existing Sphinx output where possible. |
| `bazel run //:docs_check` | `check` | Run the Sphinx `needs` builder. |
| `bazel run //:docs_link_check` | `linkcheck` | Run the Sphinx `linkcheck` builder. |
| `bazel run //:live_preview` | `live_preview` | Rebuild on edits and serve the documentation with sphinx-autobuild. |


## Layout and Bazel integration

- `cli.py` contains the complete implementation: CLI parsing, Sphinx arguments,
cache checks, bundle watch directories and action dispatch.
- `dirty_build_test.py` covers cache invalidation and mounted watch directories.
- `main_test.py` covers dispatch, build results and the Bazel environment contract.

`_declare_docs_binary()` in `docs.bzl` creates a separate `py_binary` for each
command, using the exported `cli.py` directly as its source. Each binary receives
its own `ACTION`, documentation environment and dependencies from `docs()`.

The `all_sources` filegroup is included by `//src:all_sources` so source-code
linking can traverse this Bazel package boundary.

## Configuration and build state

`docs.bzl` provides `SOURCE_DIRECTORY`, `PACKAGE_DIR`, `DATA`, and optional
configuration such as `SPHINX_CONFIG_FILE`, `SCORE_METAMODEL_YAML`,
`MOUNTS_MANIFEST`, `EXTERNAL_NEEDS_FILES`, `TEST_SOURCES` and `KNOWN_GOOD_JSON`.
Bazel provides the workspace and runfiles locations. The CLI resolves source
and output paths relative to the package containing the `docs()` call; generated
configuration is resolved through runfiles.

All actions share the package's `_build` directory. Before starting, the CLI
removes stale output if the previous build recorded warnings, the stored hash
is missing, or the contents of `MODULE.bazel`, `MODULE.bazel.lock` or the package's
`BUILD` file have changed. Successful non-preview builds record the input hash;
failed builds append a marker to `warnings.txt` to force cleanup next time.

Live preview also watches mounted bundle source directories and generated data
directories outside the main Sphinx source directory, using the same mount
resolver as the Sphinx extension.

## Tests

From the repository root:

```sh
bazel test //src/docs_cli:dirty_build_test //src/docs_cli:main_test
```

To exercise the entry script and its runfiles with an actual Sphinx build:

```sh
bazel run //src/tests/docs_bzl/scenarios/basic_docs:docs
```
Loading
Loading