diff --git a/src/extensions/score_metamodel/checks/attributes_format.py b/src/extensions/score_metamodel/checks/attributes_format.py index 248979daa..7f2551ba1 100644 --- a/src/extensions/score_metamodel/checks/attributes_format.py +++ b/src/extensions/score_metamodel/checks/attributes_format.py @@ -63,23 +63,22 @@ def check_id_length(app: Sphinx, need: NeedItem, log: CheckLogger): While the recommended limit is 30 characters, this check enforces a strict maximum of 45 characters. If the ID exceeds 45 characters, a warning is logged specifying the actual length. - Any examples that are required to have 3 parts (2x'__') have an exception, - and get 17 extra characters to compensate for the lenght of `_example_feature_` - that would be replaced by actually feature names. --- """ max_length = 45 parts = need["id"].split("__") - if parts[1] == "example_feature": + + # Any examples that are required to have 3 parts (2x'__') have an exception, + # and get 17 extra characters to compensate for the length of `_example_feature_` + # that would be replaced by actual feature names. + if len(parts) >= 2 and parts[1] == "example_feature": max_length += 17 # _example_feature_ + if len(need["id"]) > max_length: length = len(need["id"]) - if "example_feature" in need["id"]: - length -= 17 msg = ( - f"exceeds the maximum allowed length of 45 characters " - "(current length: " - f"{length})." + f"exceeds the maximum allowed length of {max_length} characters " + f"(current length: {length})." ) log.warning_for_option(need, "id", msg) diff --git a/src/extensions/score_metamodel/external_needs.py b/src/extensions/score_metamodel/external_needs.py index 44b7380ea..51f927a21 100644 --- a/src/extensions/score_metamodel/external_needs.py +++ b/src/extensions/score_metamodel/external_needs.py @@ -80,7 +80,11 @@ def parse_external_needs_sources_from_DATA(v: str) -> list[ExternalNeedsSource]: logger.debug(f"Parsing external needs sources: {v}") - data = json.loads(v) + try: + data = json.loads(v) + except json.JSONDecodeError as e: + logger.error(f"Failed to parse external needs sources from DATA {v}: {e}") + raise SystemExit(1) from e res = [res for el in data if (res := _parse_bazel_external_need(el))] logger.debug(f"Parsed external needs sources: {res}") diff --git a/src/extensions/score_sphinx_bundle/BUILD b/src/extensions/score_sphinx_bundle/BUILD index 954c172e3..113803b97 100644 --- a/src/extensions/score_sphinx_bundle/BUILD +++ b/src/extensions/score_sphinx_bundle/BUILD @@ -22,6 +22,10 @@ filegroup( py_library( name = "score_sphinx_bundle", srcs = [":all_sources"], + # Keep the shared Sphinx-Needs templates beside the extension in the + # Bazel runfiles tree. The Python extension discovers their directory from + # its own __file__ instead of receiving a path from docs.bzl. + data = ["@score_docs_as_code//src/needs_templates:files"], visibility = ["//visibility:public"], deps = all_requirements + [ "@score_docs_as_code//src/extensions:score_plantuml", diff --git a/src/extensions/score_sphinx_bundle/__init__.py b/src/extensions/score_sphinx_bundle/__init__.py index 11adca09e..f3399e507 100644 --- a/src/extensions/score_sphinx_bundle/__init__.py +++ b/src/extensions/score_sphinx_bundle/__init__.py @@ -10,6 +10,8 @@ # # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* +from pathlib import Path + import matplotlib from sphinx.application import Sphinx @@ -43,12 +45,38 @@ ] +def _needs_template_folder() -> Path: + """Return the shared Sphinx-Needs template directory. + + The extension and the templates are both part of the main ``src`` tree. + Deriving the path from ``__file__`` works for the workspace, Bazel + runfiles, and the sandbox because the extension's data files preserve that + source-tree layout. + """ + # Keep the runfiles/sandbox prefix intact; only walk from the extension's + # package directory to the sibling ``needs_templates`` directory. + # Basically: src/extensions/score_sphinx_bundle/../../needs_templates. + template_folder = Path(__file__).parents[2] / "needs_templates" + if not template_folder.is_dir(): + raise FileNotFoundError( + f"Sphinx-Needs template folder does not exist: {template_folder}" + ) + return template_folder + + def setup(app: Sphinx) -> dict[str, object]: matplotlib.rcParamsDefault["savefig.bbox"] = "tight" config_setdefault(app.config, "html_copy_source", False) config_setdefault(app.config, "html_show_sourcelink", False) + # The templates are a data dependency of this extension. Locate the + # shared directory from the extension itself instead of passing a Bazel + # label or a list of generated paths through every docs target. + config_setdefault( + app.config, "needs_template_folder", str(_needs_template_folder()) + ) + # Global settings # Note: the "sub-extensions" also set their own config values diff --git a/src/needs_templates/BUILD b/src/needs_templates/BUILD new file mode 100644 index 000000000..b6f8c2567 --- /dev/null +++ b/src/needs_templates/BUILD @@ -0,0 +1,21 @@ +# ******************************************************************************* +# 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 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +# All Sphinx-Needs templates are deliberately kept flat in this package. +# Consumers derive the common parent directory from the plural Bazel path +# expansion, so do not add templates below subdirectories here. +filegroup( + name = "files", + srcs = glob(["*.need"]), + visibility = ["//visibility:public"], +) diff --git a/src/needs_templates/example.need b/src/needs_templates/example.need new file mode 100644 index 000000000..ad3b56ee9 --- /dev/null +++ b/src/needs_templates/example.need @@ -0,0 +1 @@ +This text comes from a template