Skip to content

Commit ae6ebea

Browse files
Bugfix external_prefix regex check
Remove defined external 'id_prefixes' from to be checked links. Added another example to have an rst file inside a folder as well. Added some explanation to descriptions of needs
1 parent 2998a1e commit ae6ebea

File tree

6 files changed

+97
-5
lines changed

6 files changed

+97
-5
lines changed

MODULE.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ bazel_dep(name = "score_python_basics", version = "0.3.1")
9292
bazel_dep(name = "score_cr_checker", version = "0.2.2")
9393

9494
# This is only needed to build the examples.
95-
bazel_dep(name = "score_platform", version = "0.1.0")
95+
bazel_dep(name = "score_platform", version = "0.1.1")
9696

9797
# Grab dash
9898
bazel_dep(name = "score_dash_license_checker", version = "0.1.1")

examples/linking-both/index.rst

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,41 @@
1212
# SPDX-License-Identifier: Apache-2.0
1313
# *******************************************************************************
1414
15+
16+
.. toctree::
17+
:maxdepth: 1
18+
:glob:
19+
20+
testing/test
21+
22+
1523
Hello World
1624
=================
1725
This is a simple example of a documentation page using the `docs` tool.
1826

1927
.. stkh_req:: TestTitle
20-
:id: stkh_req__docs__test_requirement
28+
:id: stkh_req__index__test_requirement
2129
:status: valid
2230
:safety: QM
2331
:rationale: A simple requirement we need to enable a documentation build
2432
:reqtype: Functional
2533

2634
Some content to make sure we also can render this
2735
This is a link to an external need inside the 'score' documentation.
28-
:need:`SCORE_gd_req__req__attr_safety`.
36+
:need:`SCORE_gd_req__req__attr_safety`
2937
Note how it starts with the defined prefix but in UPPERCASE. This comes from sphinx-needs, `see here <https://github.com/useblocks/sphinx-needs/blob/master/sphinx_needs/external_needs.py#L119>`_
3038

39+
40+
41+
.. feat_req:: Some Title
42+
:id: feat_req__index__some_title
43+
:reqtype: Process
44+
:security: YES
45+
:safety: ASIL_D
46+
:satisfies: SCORE_stkh_req__overall_goals__reuse_of_app_soft
47+
:status: invalid
48+
49+
With this requirement we can check if the removal of the prefix is working correctly.
50+
It should remove id_prefix (SCORE _) as it's defined inside the BUILD file and remove it before it checks the leftover value
51+
against the allowed defined regex in the metamodel
52+
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
..
2+
# *******************************************************************************
3+
# Copyright (c) 2024 Contributors to the Eclipse Foundation
4+
#
5+
# See the NOTICE file(s) distributed with this work for additional
6+
# information regarding copyright ownership.
7+
#
8+
# This program and the accompanying materials are made available under the
9+
# terms of the Apache License Version 2.0 which is available at
10+
# https://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# SPDX-License-Identifier: Apache-2.0
13+
# *******************************************************************************
14+
15+
Inside a folder
16+
=================
17+
This example will help catch things and bugs when rst's are defined inside a folder.
18+
19+
.. stkh_req:: TestTitle
20+
:id: stkh_req__testing__test_requirement
21+
:status: valid
22+
:safety: QM
23+
:rationale: A simple requirement we need to enable a documentation build
24+
:reqtype: Functional
25+
26+
Some content to make sure we also can render this.
27+
This is a link to an external need inside the 'score' documentation.
28+
:need:`SCORE_gd_req__req__attr_safety`
29+
Note how it starts with the defined prefix but in UPPERCASE. This comes from sphinx-needs, `see here <https://github.com/useblocks/sphinx-needs/blob/master/sphinx_needs/external_needs.py#L119>`_
30+
31+
32+
.. feat_req:: Some Title
33+
:id: feat_req__testing__some_title
34+
:reqtype: Process
35+
:security: YES
36+
:safety: ASIL_D
37+
:satisfies: SCORE_stkh_req__overall_goals__reuse_of_app_soft
38+
:status: invalid
39+
40+
With this requirement we can check if the removal of the prefix is working correctly.
41+
It should remove id_prefix (SCORE _) as it's defined inside the BUILD file and remove it before it checks the leftover value
42+
against the 'allowed' defined regex in the metamodel
43+

src/extensions/score_metamodel/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,10 +279,13 @@ def parse_external_needs_sources(app: Sphinx, config):
279279
if "json_path" in a.keys():
280280
a["json_path"] = r + a["json_path"]
281281
app.config.needs_external_needs = x
282+
# Making the prefixes uppercase here to match sphinx_needs, as it does this internally too.
283+
app.config.allowed_external_prefixes = [z["id_prefix"].upper() for z in x]
282284

283285

284286
def setup(app: Sphinx) -> dict[str, str | bool]:
285287
app.add_config_value("external_needs_source", "", rebuild="env")
288+
app.add_config_value("allowed_external_prefixes", [], rebuild="env")
286289
app.config.needs_id_required = True
287290
app.config.needs_id_regex = "^[A-Za-z0-9_-]{6,}"
288291

src/extensions/score_metamodel/checks/check_options.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from sphinx.application import Sphinx
1616
from sphinx_needs.config import NeedType
1717
from sphinx_needs.data import NeedsInfoType
18+
from collections.abc import Generator
1819

1920
from score_metamodel import (
2021
CheckLogger,
@@ -40,6 +41,7 @@ def validate_fields(
4041
fields: dict[str, str],
4142
required: bool,
4243
field_type: str,
44+
allowed_prefixes: list[str],
4345
):
4446
"""
4547
Validates that fields (options or links) in a need match their expected patterns.
@@ -50,9 +52,18 @@ def validate_fields(
5052
:param required: Whether the fields are required (True) or optional (False).
5153
:param field_type: A string indicating the field type ('option' or 'link').
5254
"""
55+
56+
def remove_prefix(values: list[str], prefixes: list[str]) -> Generator[str, None,None]:
57+
# Memory and allocation wise better to use a generator here.
58+
# Removes any prefix allowed by configuration, if prefix is there.
59+
return (
60+
next((text.removeprefix(p) for p in prefixes if text.startswith(p)), text) for text in values
61+
)
62+
63+
5364
for field, pattern in fields.items():
54-
raw_value: str | list[str] | None = need.get(field, None)
5565

66+
raw_value: str | list[str] | None = need.get(field, None)
5667
if raw_value in [None, [], ""]:
5768
if required:
5869
log.warning_for_need(
@@ -69,6 +80,10 @@ def validate_fields(
6980
else:
7081
values = [str(raw_value)]
7182

83+
# The filter ensures that the function is only called when needed.
84+
if field_type == "link" and allowed_prefixes:
85+
values = list(remove_prefix(values,allowed_prefixes))
86+
7287
for value in values:
7388
try:
7489
if not re.match(pattern, value):
@@ -123,6 +138,9 @@ def check_options(
123138
],
124139
}
125140

141+
# If undefined this is an empty list
142+
allowed_prefixes = app.config.allowed_external_prefixes
143+
126144
for field_type, check_fields in checking_dict.items():
127145
for field_values, is_required in check_fields:
128146
validate_fields(
@@ -131,6 +149,7 @@ def check_options(
131149
field_values,
132150
required=is_required,
133151
field_type=field_type,
152+
allowed_prefixes=allowed_prefixes
134153
)
135154

136155

src/extensions/score_metamodel/checks/id_contains_feature.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,13 @@ def id_contains_feature(app: Sphinx, need: NeedsInfoType, log: CheckLogger):
3737

3838
# Get the part of the string after the first two underscores: the path
3939
feature = parts[1]
40+
41+
dir_docname = os.path.dirname(str(need.get("docname", "")))
42+
43+
# If the 'rst' file is not in a directory, the above expression will be "".
44+
# Even if the need itself has a docname. That's why we have this logic here.
45+
docname = dir_docname if dir_docname else need.get("docname", "")
4046

41-
docname = os.path.dirname(str(need.get("docname", "")))
4247
if feature not in docname:
4348
log.warning_for_option(
4449
need, "id", f"Feature '{feature}' not in path '{docname}'."

0 commit comments

Comments
 (0)