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
17 changes: 8 additions & 9 deletions src/extensions/score_metamodel/checks/attributes_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
6 changes: 5 additions & 1 deletion src/extensions/score_metamodel/external_needs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}")
Expand Down
4 changes: 4 additions & 0 deletions src/extensions/score_sphinx_bundle/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
28 changes: 28 additions & 0 deletions src/extensions/score_sphinx_bundle/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************
from pathlib import Path

import matplotlib
from sphinx.application import Sphinx

Expand Down Expand Up @@ -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

Expand Down
21 changes: 21 additions & 0 deletions src/needs_templates/BUILD
Original file line number Diff line number Diff line change
@@ -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"],
)
1 change: 1 addition & 0 deletions src/needs_templates/example.need
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This text comes from a template
Loading