Skip to content
Open
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
27 changes: 19 additions & 8 deletions docs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def _missing_requirements(deps):
fail(msg)
fail("This case should be unreachable?!")

def docs(source_dir = "docs", data = [], deps = [], scan_code = [], known_good = None):
def docs(source_dir = "docs", data = [], deps = [], scan_code = [], known_good = None, metamodel = None):
"""Creates all targets related to documentation.

By using this function, you'll get any and all updates for documentation targets in one place.
Expand All @@ -135,13 +135,24 @@ def docs(source_dir = "docs", data = [], deps = [], scan_code = [], known_good =
data: Additional data files to include in the documentation build.
deps: Additional dependencies for the documentation build.
scan_code: List of code targets to scan for source code links.
known_good: Optional label to a "known good" JSON file for source links.
metamodel: Optional label to a metamodel.yaml file. When set, the extension loads this
file instead of the default metamodel shipped with score_metamodel.
"""

call_path = native.package_name()

if call_path != "":
fail("docs() must be called from the root package. Current package: " + call_path)

metamodel_data = []
metamodel_env = {}
metamodel_opts = []
if metamodel != None:
metamodel_data = [metamodel]
metamodel_env = {"SCORE_METAMODEL_YAML": "$(location " + str(metamodel) + ")"}
metamodel_opts = ["--define=score_metamodel_yaml=$(location " + str(metamodel) + ")"]

Comment thread
a-zw marked this conversation as resolved.
module_deps = deps
deps = deps + _missing_requirements(deps)
deps = deps + [
Expand All @@ -152,7 +163,7 @@ def docs(source_dir = "docs", data = [], deps = [], scan_code = [], known_good =
sphinx_build_binary(
name = "sphinx_build",
visibility = ["//visibility:private"],
data = data,
data = data + metamodel_data,
deps = deps,
)

Expand Down Expand Up @@ -187,19 +198,19 @@ def docs(source_dir = "docs", data = [], deps = [], scan_code = [], known_good =
data_with_docs_sources = _rewrite_needs_json_to_docs_sources(data)
additional_combo_sourcelinks = _rewrite_needs_json_to_sourcelinks(data)
_merge_sourcelinks(name = "merged_sourcelinks", sourcelinks = [":sourcelinks_json"] + additional_combo_sourcelinks, known_good = known_good)
docs_data = data + [":sourcelinks_json"]
combo_data = data_with_docs_sources + [":merged_sourcelinks"]
docs_data = data + metamodel_data + [":sourcelinks_json"]
combo_data = data_with_docs_sources + metamodel_data + [":merged_sourcelinks"]

docs_env = {
"SOURCE_DIRECTORY": source_dir,
"DATA": str(data),
"SCORE_SOURCELINKS": "$(location :sourcelinks_json)",
}
} | metamodel_env
docs_sources_env = {
"SOURCE_DIRECTORY": source_dir,
"DATA": str(data_with_docs_sources),
"SCORE_SOURCELINKS": "$(location :merged_sourcelinks)",
}
} | metamodel_env
if known_good:
docs_env["KNOWN_GOOD_JSON"] = "$(location "+ known_good + ")"
docs_sources_env["KNOWN_GOOD_JSON"] = "$(location "+ known_good + ")"
Expand Down Expand Up @@ -293,10 +304,10 @@ def docs(source_dir = "docs", data = [], deps = [], scan_code = [], known_good =
"--jobs",
"auto",
"--define=external_needs_source=" + str(data),
],
] + metamodel_opts,
formats = ["needs"],
sphinx = ":sphinx_build",
tools = data,
tools = data + metamodel_data,
visibility = ["//visibility:public"],
# Persistent workers cause stale symlinks after dependency version
# changes, corrupting the Bazel cache.
Expand Down
6 changes: 4 additions & 2 deletions docs/how-to/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,10 @@ The `docs()` macro accepts the following arguments:
| Parameter | Description | Required |
|-----------|-------------|----------|
| `source_dir` | Directory of documentation source files (RST, MD) | Yes |
| `data` | List of `needs_json` targets that should be included in the documentation| No |

| `data` | List of `needs_json` targets that should be included in the documentation | No |
| `deps` | Additional Bazel Python dependencies | No |
| `scan_code` | Source code targets to scan for traceability tags | No |
| `metamodel` | Label to a custom `metamodel.yaml` that replaces the default metamodel | No |

### 4. Copy conf.py

Expand Down
23 changes: 23 additions & 0 deletions docs/reference/bazel_macros.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,29 @@ Minimal example (root ``BUILD``)
If you don't provide the necessary Sphinx packages,
this function adds its own (but checks for conflicts).

- ``scan_code`` (list of bazel labels)
Source code targets to scan for traceability tags (``req-Id:`` annotations).
Used to generate the source-code-link JSON that maps tags back to source files.

- ``metamodel`` (bazel label, optional)
Path to a custom ``metamodel.yaml`` file.
When set, the ``score_metamodel`` extension loads **this file instead of** the default metamodel.
The label is automatically added to the ``data`` and ``tools`` of every generated target
so the file is available in the Bazel sandbox at build time.
Comment thread
a-zw marked this conversation as resolved.

Example:

.. code-block:: python

docs(
source_dir = "docs",
metamodel = "//:my_metamodel.yaml",
)

The custom ``metamodel.yaml`` must follow the same schema as the default one
(see :doc:`score_metamodel </internals/extensions/metamodel>`).
When ``metamodel`` is omitted the default metamodel is used unchanged.

Edge cases
----------

Expand Down
5 changes: 4 additions & 1 deletion src/extensions/score_metamodel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,11 +228,14 @@ def postprocess_need_links(needs_types_list: list[ScoreNeedType]):

def setup(app: Sphinx) -> dict[str, str | bool]:
app.add_config_value("external_needs_source", "", rebuild="env")
app.add_config_value("score_metamodel_yaml", "", rebuild="env")
config_setdefault(app.config, "needs_id_required", True)
config_setdefault(app.config, "needs_id_regex", "^[A-Za-z0-9_-]{6,}")

# load metamodel.yaml via ruamel.yaml
metamodel = load_metamodel_data()
raw_metamodel_path = app.config.score_metamodel_yaml
override_path = Path(raw_metamodel_path) if raw_metamodel_path else None
metamodel = load_metamodel_data(override_path)

# Extend sphinx-needs config rather than overwriting
app.config.needs_types += metamodel.needs_types
Expand Down
9 changes: 9 additions & 0 deletions src/extensions/score_metamodel/tests/test_metamodel_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ def load_model_data(model_file: str) -> str:
return f.read()


def test_load_metamodel_data_explicit_path():
"""When an explicit path is given, load_metamodel_data reads that file."""
explicit_path = MODEL_DIR / "simple_model.yaml"
result = load_metamodel_data(yaml_path=explicit_path)

assert len(result.needs_types) == 1
assert result.needs_types[0]["directive"] == "type1"


def test_load_metamodel_data():
model_data: str = load_model_data("simple_model.yaml")

Expand Down
9 changes: 7 additions & 2 deletions src/extensions/score_metamodel/yaml_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,11 +182,16 @@ def _collect_all_custom_options(
}


def load_metamodel_data() -> MetaModelData:
def load_metamodel_data(yaml_path: Path | None = None) -> MetaModelData:
"""
Load metamodel.yaml and prepare data fields as needed for sphinx-needs.

Args:
yaml_path: Path to the metamodel YAML file. When None, the default
metamodel shipped with this extension is used.
"""
yaml_path = Path(__file__).resolve().parent / "metamodel.yaml"
if yaml_path is None:
yaml_path = Path(__file__).resolve().parent / "metamodel.yaml"
Comment thread
a-zw marked this conversation as resolved.

with open(yaml_path, encoding="utf-8") as f:
data = cast(dict[str, Any], YAML().load(f))
Expand Down
4 changes: 4 additions & 0 deletions src/incremental.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ def get_env(name: str) -> str:
f"--define=external_needs_source={get_env('DATA')}",
]

metamodel_yaml = os.environ.get("SCORE_METAMODEL_YAML", "")
if metamodel_yaml:
base_arguments.append(f"--define=score_metamodel_yaml={metamodel_yaml}")

# configure sphinx build with GitHub user and repo from CLI
if args.github_user and args.github_repo:
base_arguments.append(f"-A=github_user={args.github_user}")
Expand Down
Loading