Skip to content

Commit 1886707

Browse files
authored
Merge branch 'main' into vohae_saf_analysis
Signed-off-by: Volker Häussler <volker.haeussler@qorix.ai>
2 parents e5f5f2a + a4e19d4 commit 1886707

20 files changed

Lines changed: 1497 additions & 703 deletions

.bazelrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ build --incompatible_default_to_explicit_init_py
1010

1111
common --registry=https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/
1212
common --registry=https://bcr.bazel.build
13+
14+
common --incompatible_disallow_empty_glob

docs.bzl

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ load("@rules_pkg//pkg:mappings.bzl", "pkg_files")
4444
load("@rules_pkg//pkg:tar.bzl", "pkg_tar")
4545
load("@rules_python//sphinxdocs:sphinx.bzl", "sphinx_build_binary", "sphinx_docs")
4646
load("@rules_python//sphinxdocs:sphinx_docs_library.bzl", "sphinx_docs_library")
47-
load("@score_docs_as_code//src/extensions/score_source_code_linker:collect_source_files.bzl", "parse_source_files_for_needs_links")
4847
load("@score_python_basics//:defs.bzl", "score_virtualenv")
4948

5049
sphinx_requirements = all_requirements + [
@@ -58,21 +57,14 @@ sphinx_requirements = all_requirements + [
5857
"@score_docs_as_code//src/extensions/score_source_code_linker:score_source_code_linker",
5958
]
6059

61-
def docs(source_files_to_scan_for_needs_links = None, source_dir = "docs", conf_dir = "docs", build_dir_for_incremental = "_build", docs_targets = []):
60+
def docs(source_files_to_scan_for_needs_links = None, source_dir = "docs", conf_dir = "docs", build_dir_for_incremental = "_build", docs_targets = [], deps = []):
6261
"""
6362
Creates all targets related to documentation.
6463
By using this function, you'll get any and all updates for documentation targets in one place.
6564
Current restrictions:
6665
* only callable from 'docs/BUILD'
6766
"""
6867

69-
# Parse source files for needs links
70-
# This needs to be created to generate a target, otherwise it won't execute as dependency for other macros
71-
parse_source_files_for_needs_links(
72-
name = "score_source_code_parser",
73-
srcs_and_deps = source_files_to_scan_for_needs_links if source_files_to_scan_for_needs_links else [],
74-
)
75-
7668
# We are iterating over all provided 'targets' in order to allow for automatic generation of them without
7769
# needing to modify the underlying 'docs.bzl' file.
7870
for target in docs_targets:
@@ -83,8 +75,8 @@ def docs(source_files_to_scan_for_needs_links = None, source_dir = "docs", conf_
8375
sphinx_build_binary(
8476
name = "sphinx_build" + suffix,
8577
visibility = ["//visibility:public"],
86-
data = ["@score_docs_as_code//src:docs_assets", "@score_docs_as_code//src:score_extension_files"] + external_needs_deps,
87-
deps = sphinx_requirements,
78+
data = ["@score_docs_as_code//src:docs_assets", "@score_docs_as_code//src:docs_as_code_py_modules"] + external_needs_deps,
79+
deps = sphinx_requirements + deps,
8880
)
8981
_incremental(
9082
incremental_name = "incremental" + suffix,
@@ -94,6 +86,7 @@ def docs(source_files_to_scan_for_needs_links = None, source_dir = "docs", conf_
9486
build_dir = build_dir_for_incremental,
9587
external_needs_deps = external_needs_deps,
9688
external_needs_def = external_needs_def,
89+
extra_dependencies = deps,
9790
)
9891
_docs(
9992
name = "docs" + suffix,
@@ -113,7 +106,7 @@ def docs(source_files_to_scan_for_needs_links = None, source_dir = "docs", conf_
113106
# Virtual python environment for working on the documentation (esbonio).
114107
# incl. python support when working on conf.py and sphinx extensions.
115108
# creates :ide_support target for virtualenv
116-
_ide_support()
109+
_ide_support(deps)
117110

118111
# creates 'needs.json' build target
119112

@@ -136,7 +129,7 @@ def _incremental(incremental_name = "incremental", live_name = "live_preview", s
136129
srcs = ["@score_docs_as_code//src:incremental.py"],
137130
deps = dependencies,
138131
# TODO: Figure out if we need all dependencies as data here or not.
139-
data = [":score_source_code_parser", "@score_docs_as_code//src:plantuml", "@score_docs_as_code//src:docs_assets"] + dependencies + external_needs_deps,
132+
data = ["@score_docs_as_code//src:plantuml", "@score_docs_as_code//src:docs_assets"] + dependencies + external_needs_deps,
140133
env = {
141134
"SOURCE_DIRECTORY": source_dir,
142135
"CONF_DIRECTORY": conf_dir,
@@ -160,11 +153,11 @@ def _incremental(incremental_name = "incremental", live_name = "live_preview", s
160153
},
161154
)
162155

163-
def _ide_support():
156+
def _ide_support(extra_dependencies):
164157
score_virtualenv(
165158
name = "ide_support",
166159
venv_name = ".venv_docs",
167-
reqs = sphinx_requirements,
160+
reqs = sphinx_requirements + extra_dependencies,
168161
)
169162

170163
def _docs(name = "docs", suffix = "", format = "html", external_needs_deps = list(), external_needs_def = list()):
@@ -190,7 +183,7 @@ def _docs(name = "docs", suffix = "", format = "html", external_needs_deps = lis
190183
"**/*.json",
191184
"**/*.csv",
192185
"**/*.inc",
193-
], exclude = ["**/tests/*"]),
186+
], exclude = ["**/tests/*"], allow_empty = True),
194187
config = ":conf.py",
195188
extra_opts = [
196189
"-W",
@@ -204,7 +197,6 @@ def _docs(name = "docs", suffix = "", format = "html", external_needs_deps = lis
204197
"manual",
205198
],
206199
tools = [
207-
":score_source_code_parser",
208200
"@score_docs_as_code//src:plantuml",
209201
"@score_docs_as_code//src:docs_assets",
210202
] + external_needs_deps,
@@ -213,7 +205,7 @@ def _docs(name = "docs", suffix = "", format = "html", external_needs_deps = lis
213205

214206
native.filegroup(
215207
name = "assets" + target_suffix,
216-
srcs = native.glob(["_assets/**"]),
208+
srcs = native.glob(["_assets/**"], allow_empty = True),
217209
visibility = ["//visibility:public"],
218210
)
219211

docs/BUILD

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,4 @@ docs(
4848
},
4949
],
5050
source_dir = "docs",
51-
source_files_to_scan_for_needs_links = [
52-
"//src:score_extension_files",
53-
],
5451
)

docs/product/extensions/source_code_linker.md

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ The extension uses two main components to integrate with Bazel:
1616
- Handles dependency tracking for incremental builds
1717

1818
2. `parse_source_files.py`
19-
- Scans input files for template tags (e.g., `# req-traceability:`)
19+
- Scans input files for template tags (e.g., "#<!-- comment prevents parsing this occurance --> req-traceability:")
2020
- Retrieves git information (hash, file location)
2121
- Generates mapping file with requirement IDs and links
2222

@@ -37,16 +37,27 @@ The extension uses two main components to integrate with Bazel:
3737
- Gets current git hash for each file
3838
- Constructs GitHub URLs with format:
3939
`{base_url}/{repo}/blob/{hash}/{file}#L{line_nr}`
40-
**Note:** The base_url is defined in `parse_source_files.py`. Currently set to: `https://github.com/eclipse-score/score/blob/`
40+
**Note:** The base_url is defined in `parse_source_files.py`. Currently set to: `https://github.com/eclipse-score/score/blob/`
4141

4242
Produces JSON mapping file:
43-
```json
44-
{
45-
"REQ_ID": [
46-
"github_link1",
47-
"github_link2" // If multiple code-links exist
48-
]
49-
}
43+
The strings are split here to not enable tracking by the source code linker.
44+
```python
45+
[
46+
{
47+
"file": "src/implementation1.py",
48+
"line": 3,
49+
"tag":"#" + " req-Id:",
50+
"need": "TREQ_ID_1",
51+
"full_line": "#"+" req-Id: TREQ_ID_1"
52+
},
53+
{
54+
"file": "src/implementation2.py",
55+
"line": 3,
56+
"tag":"#" + " req-Id:",
57+
"need": "TREQ_ID_1",
58+
"full_line": "#"+" req-Id: TREQ_ID_1"
59+
},
60+
]
5061
```
5162

5263
<br>
@@ -86,7 +97,7 @@ The extension hooks into Sphinx's build process. It attaches to the `env-updated
8697

8798
### Adding Places to Search
8899

89-
You can easily add files to be searched by adding targets / files to the deps inside the
100+
You can easily add files to be searched by adding targets / files to the deps inside the
90101
`collect_source_files_for_score_source_code_linker` in `docs/BUILD`.
91102
See here:
92103

@@ -126,7 +137,7 @@ WARNING: Could not find TREQ_ID_200 in the needs id's. Found in file(s):['_tooli
126137

127138
### Quickly Finding Source Links
128139

129-
The easiest and quickest way to find source_code_link options is to just search for the option `source_code_link`. It should give you all rst files
140+
The easiest and quickest way to find source_code_link options is to just search for the option `source_code_link`. It should give you all rst files
130141
where the option is not empty.
131142

132143
### Executing Tests

src/BUILD

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -118,21 +118,6 @@ py_library(
118118
visibility = ["//visibility:public"],
119119
)
120120

121-
filegroup(
122-
name = "score_extension_files",
123-
srcs = glob(
124-
[
125-
"src/**",
126-
],
127-
exclude = [
128-
"**/test/**",
129-
"**/tests/**",
130-
"**/__pycache__/**",
131-
],
132-
) + [":docs_as_code_py_modules"],
133-
visibility = ["//visibility:public"],
134-
)
135-
136121
filegroup(
137122
name = "docs_assets",
138123
srcs = glob([
@@ -153,17 +138,6 @@ filegroup(
153138
visibility = ["//visibility:public"],
154139
)
155140

156-
# Needed for 'test_rules_file_based'
157-
filegroup(
158-
name = "test_rst_files",
159-
srcs = glob([
160-
"extensions/**/*.rst",
161-
"extensions/**/*.py",
162-
"conf.py",
163-
]),
164-
visibility = ["//visibility:public"],
165-
)
166-
167141
dash_license_checker(
168142
src = ":requirements_lock",
169143
file_type = "requirements",

src/extensions/score_metamodel/BUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ score_py_pytest(
3333
size = "small",
3434
srcs = glob(["tests/*.py"]),
3535
# All requirements already in the library so no need to have it double
36-
data = ["//src:test_rst_files"] + glob(
36+
data = glob(
3737
["tests/**/*.rst"],
3838
),
3939
deps = [":score_metamodel"],

src/extensions/score_metamodel/__init__.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,17 @@
1111
# SPDX-License-Identifier: Apache-2.0
1212
# *******************************************************************************
1313
import importlib
14-
import pkgutil
1514
import json
1615
import os
17-
16+
import pkgutil
1817
from collections.abc import Callable
1918
from pathlib import Path
2019

21-
2220
from ruamel.yaml import YAML
2321
from sphinx.application import Sphinx
2422
from sphinx_needs import logging
25-
from sphinx_needs.data import NeedsInfoType, SphinxNeedsData, NeedsView
23+
from sphinx_needs.data import NeedsInfoType, NeedsView, SphinxNeedsData
24+
2625
from .log import CheckLogger
2726

2827
logger = logging.get_logger(__name__)
@@ -81,7 +80,9 @@ def _run_checks(app: Sphinx, exception: Exception | None) -> None:
8180

8281
logger.debug(f"Running checks for {len(needs_all_needs)} needs")
8382

84-
prefix = str(Path(app.srcdir).relative_to(Path.cwd()))
83+
ws_root = os.environ.get("BUILD_WORKSPACE_DIRECTORY", None)
84+
cwd_or_ws_root = Path(ws_root) if ws_root else Path.cwd()
85+
prefix = str(Path(app.srcdir).relative_to(cwd_or_ws_root))
8586

8687
log = CheckLogger(logger, prefix)
8788

src/extensions/score_metamodel/checks/id_contains_feature.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
# SPDX-License-Identifier: Apache-2.0
1212
# *******************************************************************************
1313
import os
14+
import re
1415

1516
from sphinx.application import Sphinx
1617
from sphinx_needs.data import NeedsInfoType
@@ -37,6 +38,7 @@ def id_contains_feature(app: Sphinx, need: NeedsInfoType, log: CheckLogger):
3738

3839
# Get the part of the string after the first two underscores: the path
3940
feature = parts[1]
41+
featureparts = re.split(r"[_-]", feature)
4042

4143
dir_docname = os.path.dirname(str(need.get("docname", "")))
4244

@@ -45,7 +47,22 @@ def id_contains_feature(app: Sphinx, need: NeedsInfoType, log: CheckLogger):
4547
# NOTE: This does not match the process requirements
4648
docname = dir_docname if dir_docname else need.get("docname", "")
4749

48-
if feature not in docname:
50+
# allow if any feature part is contained in UID
51+
foundfeatpart = any(
52+
featurepart.lower() in docname.lower()
53+
for featurepart in featureparts
54+
if featureparts
55+
)
56+
57+
# allow abbreviation of the feature
58+
initials = "".join(
59+
featurepart[0].lower() for featurepart in featureparts if len(featureparts) > 1
60+
)
61+
foundinitials = initials in docname.lower()
62+
63+
if not (foundfeatpart or foundinitials):
4964
log.warning_for_option(
50-
need, "id", f"Feature '{feature}' not in path '{docname}'."
65+
need,
66+
"id",
67+
f"Featurepart '{featureparts}' not in path '{docname}' or abbreviation not ok, expected: '{initials}'.",
5168
)

src/extensions/score_metamodel/tests/rst/id_contains_feature/test_id_contains_feature.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@
1313
# *******************************************************************************
1414
#CHECK: id_contains_feature
1515

16-
.. Feature is not in the path of the RST file
17-
#EXPECT: std_wp__test__abcd.id (std_wp__test__abcd): Feature 'test' not in path
16+
.. Feature is deeper in the path of the RST file
17+
.. This is now explicitly allowed
18+
#EXPECT-NOT: std_wp__test__abcd.id (std_wp__test__abcd): Feature 'test' not in path
1819

1920
.. std_wp:: This is a test
2021
:id: std_wp__test__abcd

src/extensions/score_plantuml.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def get_runfiles_dir() -> Path:
5353
# But we need to find it first.
5454
logger.debug("Running outside bazel.")
5555

56-
git_root = Path(__file__).resolve()
56+
git_root = Path.cwd().resolve()
5757
while not (git_root / ".git").exists():
5858
git_root = git_root.parent
5959
if git_root == Path("/"):

0 commit comments

Comments
 (0)