diff --git a/BUILD b/BUILD index 21a92e427..adbbd688a 100644 --- a/BUILD +++ b/BUILD @@ -13,7 +13,7 @@ load("@aspect_rules_py//py:defs.bzl", "py_library") load("@score_tooling//:defs.bzl", "cli_helper", "copyright_checker") -load("//:docs.bzl", "docs") +load("//:docs.bzl", "docs", "sourcelinks_json") package(default_visibility = ["//visibility:public"]) @@ -29,11 +29,29 @@ copyright_checker( visibility = ["//visibility:public"], ) +sourcelinks_json( + name = "sourcelinks_json", + srcs = [ + "//src:all_sources", + "//src/extensions/score_draw_uml_funcs:all_sources", + "//src/extensions/score_header_service:all_sources", + "//src/extensions/score_layout:all_sources", + "//src/extensions/score_metamodel:all_sources", + "//src/extensions/score_source_code_linker:all_sources", + "//src/extensions/score_sphinx_bundle:all_sources", + "//src/extensions/score_sync_toml:all_sources", + "//src/find_runfiles:all_sources", + "//src/helper_lib:all_sources", + ], + visibility = ["//visibility:public"], +) + docs( data = [ "@score_process//:needs_json", ], source_dir = "docs", + sourcelinks = [":sourcelinks_json"], ) cli_helper( diff --git a/MODULE.bazel b/MODULE.bazel index c7f9c56aa..33c76fc9c 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -104,7 +104,7 @@ bazel_dep(name = "score_process", version = "1.4.2") # Add Linter bazel_dep(name = "rules_multitool", version = "1.9.0") -bazel_dep(name = "score_tooling", version = "1.0.2") +bazel_dep(name = "score_tooling", version = "1.0.5") multitool_root = use_extension("@rules_multitool//multitool:extension.bzl", "multitool") use_repo(multitool_root, "actionlint_hub", "multitool", "ruff_hub", "shellcheck_hub", "yamlfmt_hub") diff --git a/docs.bzl b/docs.bzl index 00f1c676c..e65e7d00f 100644 --- a/docs.bzl +++ b/docs.bzl @@ -56,12 +56,40 @@ def _rewrite_needs_json_to_docs_sources(labels): out.append(s) return out -def docs(source_dir = "docs", data = [], deps = []): +def _merge_sourcelinks(name, sourcelinks): + """Merge multiple sourcelinks JSON files into a single file. + + Args: + name: Name for the merged sourcelinks target + sourcelinks: List of sourcelinks JSON file targets """ - Creates all targets related to documentation. + + native.genrule( + name = name, + srcs = sourcelinks, + outs = [name + ".json"], + cmd = """ + $(location //scripts:merge_sourcelinks) \ + --output $@ \ + $(SRCS) + """, + tools = ["//scripts:merge_sourcelinks"], + ) + +def docs(source_dir = "docs", data = [], deps = [], sourcelinks = []): + """Creates all targets related to documentation. + By using this function, you'll get any and all updates for documentation targets in one place. + + Args: + source_dir: The source directory containing documentation files. Defaults to "docs". + data: Additional data files to include in the documentation build. + deps: Additional dependencies for the documentation build. + sourcelinks: Source code links configuration for traceability. """ + _merge_sourcelinks(name = "merged_sourcelinks", sourcelinks = sourcelinks) + call_path = native.package_name() if call_path != "": @@ -106,12 +134,13 @@ def docs(source_dir = "docs", data = [], deps = []): name = "docs", tags = ["cli_help=Build documentation:\nbazel run //:docs"], srcs = ["@score_docs_as_code//src:incremental.py"], - data = data, + data = data + [":merged_sourcelinks"], deps = deps, env = { "SOURCE_DIRECTORY": source_dir, "DATA": str(data), "ACTION": "incremental", + "SCORE_SOURCELINKS": "$(location :merged_sourcelinks)", }, ) @@ -119,12 +148,13 @@ def docs(source_dir = "docs", data = [], deps = []): name = "docs_combo_experimental", tags = ["cli_help=Build full documentation with all dependencies:\nbazel run //:docs_combo_experimental"], srcs = ["@score_docs_as_code//src:incremental.py"], - data = data_with_docs_sources, + data = data_with_docs_sources + [":merged_sourcelinks"], deps = deps, env = { "SOURCE_DIRECTORY": source_dir, "DATA": str(data_with_docs_sources), "ACTION": "incremental", + "SCORE_SOURCELINKS": "$(location :merged_sourcelinks)", }, ) @@ -132,12 +162,13 @@ def docs(source_dir = "docs", data = [], deps = []): name = "docs_check", tags = ["cli_help=Verify documentation:\nbazel run //:docs_check"], srcs = ["@score_docs_as_code//src:incremental.py"], - data = data, + data = data + [":merged_sourcelinks"], deps = deps, env = { "SOURCE_DIRECTORY": source_dir, "DATA": str(data), "ACTION": "check", + "SCORE_SOURCELINKS": "$(location :merged_sourcelinks)", }, ) @@ -145,12 +176,13 @@ def docs(source_dir = "docs", data = [], deps = []): name = "live_preview", tags = ["cli_help=Live preview documentation in the browser:\nbazel run //:live_preview"], srcs = ["@score_docs_as_code//src:incremental.py"], - data = data, + data = data + [":merged_sourcelinks"], deps = deps, env = { "SOURCE_DIRECTORY": source_dir, "DATA": str(data), "ACTION": "live_preview", + "SCORE_SOURCELINKS": "$(location :merged_sourcelinks)", }, ) @@ -158,12 +190,13 @@ def docs(source_dir = "docs", data = [], deps = []): name = "live_preview_combo_experimental", tags = ["cli_help=Live preview full documentation with all dependencies in the browser:\nbazel run //:live_preview_combo_experimental"], srcs = ["@score_docs_as_code//src:incremental.py"], - data = data_with_docs_sources, + data = data_with_docs_sources + [":merged_sourcelinks"], deps = deps, env = { "SOURCE_DIRECTORY": source_dir, "DATA": str(data_with_docs_sources), "ACTION": "live_preview", + "SCORE_SOURCELINKS": "$(location :merged_sourcelinks)", }, ) @@ -193,3 +226,29 @@ def docs(source_dir = "docs", data = [], deps = []): tools = data, visibility = ["//visibility:public"], ) + +def sourcelinks_json(name, srcs, visibility = None): + """ + Creates a target that generates a JSON file with source code links. + + See https://eclipse-score.github.io/docs-as-code/main/how-to/source_to_doc_links.html + + Args: + name: Name of the target + srcs: Source files to scan for traceability tags + visibility: Visibility of the target + """ + output_file = name + ".json" + + native.genrule( + name = name, + srcs = srcs, + outs = [output_file], + cmd = """ + $(location //scripts:generate_sourcelinks) \ + --output $@ \ + $(SRCS) + """, + tools = ["//scripts:generate_sourcelinks"], + visibility = visibility, + ) diff --git a/docs/how-to/source_to_doc_links.rst b/docs/how-to/source_to_doc_links.rst index f36866a30..3763b6d71 100644 --- a/docs/how-to/source_to_doc_links.rst +++ b/docs/how-to/source_to_doc_links.rst @@ -2,14 +2,65 @@ Reference Docs in Source Code ============================= In your C++/Rust/Python source code, you want to reference requirements (needs). -The docs-as-code tool will create backlinks in the documentation. +The docs-as-code tool will create backlinks in the documentation in two steps: + +1. You add a special comment in your source code that references the need ID. +2. Scan for those comments and provide needs links to your documentation. + +For an example result, look at the attribute ``source_code_link`` +of :need:`tool_req__docs_common_attr_title`. + +Comments in Source Code +----------------------- Use a comment and start with ``req-Id:`` or ``req-traceability:`` followed by the need ID. .. code-block:: python - # req-Id: TOOL_REQ__EXAMPLE_ID - # req-traceability: TOOL_REQ__EXAMPLE_ID + # req-Id: TOOL_REQ__EXAMPLE_ID + # req-traceability: TOOL_REQ__EXAMPLE_ID -For an example, look at the attribute ``source_code_link`` -of :need:`tool_req__docs_common_attr_title`. +For other languages (C++, Rust, etc.), use the appropriate comment syntax. + +Scanning Source Code for Links +------------------------------ + +In you ``BUILD`` files, you specify which source files to scan +with ``filegroup`` or ``glob`` or whatever Bazel mechanism you prefer. +Then, you use the ``sourcelinks_json`` rule to scan those files. +Finally, pass the scan results to the ``docs`` rule as ``sourcelinks`` attribute. + + +.. code-block:: starlark + :emphasize-lines: 1, 12, 26 + :linenos: + + load("//:docs.bzl", "docs", "sourcelinks_json") + + filegroup( + name = "some_sources", + srcs = [ + "foo.py", + "bar.cpp", + "data.yaml", + ] + glob(["subdir/**/.py"]), + ) + + sourcelinks_json( + name = "my_source_links", + srcs = [ + ":some_sources", + "//src:all_sources", + # whatever + ], + ) + + docs( + data = [ + "@score_process//:needs_json", + ], + source_dir = "docs", + sourcelinks = [":my_source_links"], + ) + +Since the source links are Bazel targets, you can easily reference other modules as well. diff --git a/scripts/BUILD b/scripts/BUILD new file mode 100644 index 000000000..ab9f0a9f6 --- /dev/null +++ b/scripts/BUILD @@ -0,0 +1,32 @@ +# ******************************************************************************* +# 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 Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +load("@aspect_rules_py//py:defs.bzl", "py_binary") +load("@pip_process//:requirements.bzl", "all_requirements") + +py_binary( + name = "generate_sourcelinks", + srcs = ["generate_sourcelinks_cli.py"], + main = "generate_sourcelinks_cli.py", + visibility = ["//visibility:public"], + deps = [ + "//src/extensions/score_source_code_linker", + ] + all_requirements, +) + +py_binary( + name = "merge_sourcelinks", + srcs = ["merge_sourcelinks.py"], + main = "merge_sourcelinks.py", + visibility = ["//visibility:public"], +) diff --git a/scripts/generate_sourcelinks_cli.py b/scripts/generate_sourcelinks_cli.py new file mode 100644 index 000000000..a70b878a0 --- /dev/null +++ b/scripts/generate_sourcelinks_cli.py @@ -0,0 +1,72 @@ +# ******************************************************************************* +# 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 Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +""" +CLI tool to generate source code links JSON from source files. +This is used by the Bazel sourcelinks_json rule to create a JSON file +with all source code links for documentation needs. +""" + +import argparse +import logging +import sys +from pathlib import Path + +from src.extensions.score_source_code_linker.generate_source_code_links_json import ( + _extract_references_from_file, +) +from src.extensions.score_source_code_linker.needlinks import ( + store_source_code_links_json, +) + +logging.basicConfig(level=logging.INFO, format="%(message)s") +logger = logging.getLogger(__name__) + + +def main(): + parser = argparse.ArgumentParser( + description="Generate source code links JSON from source files" + ) + parser.add_argument( + "--output", + required=True, + type=Path, + help="Output JSON file path", + ) + parser.add_argument( + "files", + nargs="*", + type=Path, + help="Source files to scan for traceability tags", + ) + + args = parser.parse_args() + + all_need_references = [] + for file_path in args.files: + abs_file_path = file_path.resolve() + if abs_file_path.exists(): + references = _extract_references_from_file( + abs_file_path.parent, Path(abs_file_path.name) + ) + all_need_references.extend(references) + + store_source_code_links_json(args.output, all_need_references) + logger.info( + f"Found {len(all_need_references)} need references in {len(args.files)} files" + ) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/merge_sourcelinks.py b/scripts/merge_sourcelinks.py new file mode 100644 index 000000000..2d9141f22 --- /dev/null +++ b/scripts/merge_sourcelinks.py @@ -0,0 +1,64 @@ +# ******************************************************************************* +# Copyright (c) 2025 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 Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +""" +Merge multiple sourcelinks JSON files into a single JSON file. +""" + +import argparse +import json +import logging +import sys +from pathlib import Path + +logging.basicConfig(level=logging.INFO, format="%(message)s") +logger = logging.getLogger(__name__) + + +def main(): + parser = argparse.ArgumentParser( + description="Merge multiple sourcelinks JSON files into one" + ) + parser.add_argument( + "--output", + required=True, + type=Path, + help="Output merged JSON file path", + ) + parser.add_argument( + "files", + nargs="*", + type=Path, + help="Input JSON files to merge", + ) + + args = parser.parse_args() + + merged = [] + for json_file in args.files: + if json_file.exists(): + with open(json_file) as f: + data = json.load(f) + if isinstance(data, list): + merged.extend(data) + + args.output.parent.mkdir(parents=True, exist_ok=True) + with open(args.output, "w") as f: + json.dump(merged, f, indent=2, ensure_ascii=False) + + logger.info(f"Merged {len(args.files)} files into {len(merged)} total references") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/BUILD b/src/BUILD index ddf506de1..f45f14fd7 100644 --- a/src/BUILD +++ b/src/BUILD @@ -10,14 +10,11 @@ # # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* + load("@aspect_rules_lint//format:defs.bzl", "format_multirun", "format_test") -load("@aspect_rules_py//py:defs.bzl", "py_binary", "py_library") -load("@pip_process//:requirements.bzl", "all_requirements", "requirement") -load("@rules_pkg//pkg:mappings.bzl", "pkg_files") -load("@rules_pkg//pkg:tar.bzl", "pkg_tar") +load("@aspect_rules_py//py:defs.bzl", "py_library") load("@rules_python//python:pip.bzl", "compile_pip_requirements") -load("@rules_python//sphinxdocs:sphinx.bzl", "sphinx_build_binary") -load("@score_tooling//:defs.bzl", "dash_license_checker", "score_virtualenv") +load("@score_tooling//:defs.bzl", "dash_license_checker") # These are only exported because they're passed as files to the //docs.bzl # macros, and thus must be visible to other packages. They should only be @@ -28,6 +25,25 @@ exports_files( "requirements.txt", "incremental.py", "dummy.py", + "generate_sourcelinks_cli.py", + ], + visibility = ["//visibility:public"], +) + +filegroup( + name = "all_sources", + srcs = glob( + ["*.py"], + ) + [ + "//src/extensions/score_draw_uml_funcs:all_sources", + "//src/extensions/score_header_service:all_sources", + "//src/extensions/score_layout:all_sources", + "//src/extensions/score_metamodel:all_sources", + "//src/extensions/score_source_code_linker:all_sources", + "//src/extensions/score_sphinx_bundle:all_sources", + "//src/extensions/score_sync_toml:all_sources", + "//src/find_runfiles:all_sources", + "//src/helper_lib:all_sources", ], visibility = ["//visibility:public"], ) diff --git a/src/extensions/score_draw_uml_funcs/BUILD b/src/extensions/score_draw_uml_funcs/BUILD index 21d8622e4..b16000a61 100644 --- a/src/extensions/score_draw_uml_funcs/BUILD +++ b/src/extensions/score_draw_uml_funcs/BUILD @@ -13,11 +13,15 @@ load("@aspect_rules_py//py:defs.bzl", "py_library") load("@pip_process//:requirements.bzl", "all_requirements") +filegroup( + name = "all_sources", + srcs = glob(["*.py"]), + visibility = ["//visibility:public"], +) + py_library( name = "score_draw_uml_funcs", - srcs = glob( - ["*.py"], - ), + srcs = [":all_sources"], imports = ["."], visibility = ["//visibility:public"], # TODO: Figure out if all requirements are needed or if we can break it down a bit diff --git a/src/extensions/score_header_service/BUILD b/src/extensions/score_header_service/BUILD index d7a7b65cc..481858112 100644 --- a/src/extensions/score_header_service/BUILD +++ b/src/extensions/score_header_service/BUILD @@ -10,16 +10,20 @@ # # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* + load("@aspect_rules_py//py:defs.bzl", "py_library") load("@pip_process//:requirements.bzl", "all_requirements") load("@score_tooling//:defs.bzl", "score_py_pytest") +filegroup( + name = "all_sources", + srcs = glob(["*.py"]), + visibility = ["//visibility:public"], +) + py_library( name = "score_header_service", - srcs = glob( - ["*.py"], - exclude = ["test/**"], - ), + srcs = [":all_sources"], imports = ["."], visibility = ["//visibility:public"], # TODO: Figure out if all requirements are needed or if we can break it down a bit diff --git a/src/extensions/score_layout/BUILD b/src/extensions/score_layout/BUILD index d6d472746..8e21188de 100644 --- a/src/extensions/score_layout/BUILD +++ b/src/extensions/score_layout/BUILD @@ -13,17 +13,23 @@ load("@aspect_rules_py//py:defs.bzl", "py_library") load("@pip_process//:requirements.bzl", "requirement") -py_library( - name = "score_layout", +filegroup( + name = "all_sources", srcs = glob([ "*.py", - # Adding assets as src instead of data ensures they are included in the - # library as they would normally be, and we do not need to go through bazel's - # RUNFILES_DIR mechanism to access them. This makes the code much simpler. - # And it makes the library far easier extractable from bazel into a normal - # python package if we ever want to do that. - "assets/**", + "assets/**/*", ]), + visibility = ["//visibility:public"], +) + +py_library( + name = "score_layout", + srcs = [":all_sources"], + # Adding assets as src instead of data ensures they are included in the + # library as they would normally be, and we do not need to go through bazel's + # RUNFILES_DIR mechanism to access them. This makes the code much simpler. + # And it makes the library far easier extractable from bazel into a normal + # python package if we ever want to do that. imports = ["."], visibility = ["//visibility:public"], deps = [requirement("sphinx")], diff --git a/src/extensions/score_metamodel/BUILD b/src/extensions/score_metamodel/BUILD index 40cb645f4..cc0dd2484 100644 --- a/src/extensions/score_metamodel/BUILD +++ b/src/extensions/score_metamodel/BUILD @@ -10,20 +10,44 @@ # # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* + load("@aspect_rules_py//py:defs.bzl", "py_library") load("@pip_process//:requirements.bzl", "all_requirements") load("@score_tooling//:defs.bzl", "score_py_pytest") -py_library( - name = "score_metamodel", +filegroup( + name = "sources", + srcs = glob( + [ + "*.py", + "*.yaml", + "*.json", + "checks/*.py", + ], + ), +) + +filegroup( + name = "tests", srcs = glob( - ["**/*.py"], - ) + ["metamodel.yaml"], - data = glob(["*.yaml"]), # Needed to remove 'resolving of symlink' in score_metamodel.__init__ - imports = [ - ".", + ["tests/*.py"], + ), +) + +filegroup( + name = "all_sources", + srcs = [ + ":sources", + ":tests", ], visibility = ["//visibility:public"], +) + +py_library( + name = "score_metamodel", + srcs = [":sources"], + imports = ["."], + visibility = ["//visibility:public"], # TODO: Figure out if all requirements are needed or if we can break it down a bit deps = all_requirements + ["@score_docs_as_code//src/helper_lib"], ) @@ -37,7 +61,7 @@ score_py_pytest( [ "tests/**/*.rst", "tests/**/*.yaml", - ], + ] + ["tests/rst/conf.py"], ), deps = [":score_metamodel"], ) diff --git a/src/extensions/score_source_code_linker/BUILD b/src/extensions/score_source_code_linker/BUILD index 7a662df3b..8dd7deb11 100644 --- a/src/extensions/score_source_code_linker/BUILD +++ b/src/extensions/score_source_code_linker/BUILD @@ -10,31 +10,42 @@ # # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* -#******************************************************************************* -# Copyright (c) 2025 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 Version 2.0 which is available at -# https://www.apache.org/licenses/LICENSE-2.0 -# -# SPDX-License-Identifier: Apache-2.0 -# ******************************************************************************* -load("@aspect_rules_py//py:defs.bzl", "py_binary", "py_library") -load("@pip_process//:requirements.bzl", "all_requirements") + +load("@aspect_rules_py//py:defs.bzl", "py_library") load("@score_tooling//:defs.bzl", "score_py_pytest") -py_library( - name = "score_source_code_linker", +filegroup( + name = "sources", srcs = glob( - ["**/*.py"], - exclude = ["tests/*.py"], + ["*.py"], ), +) + +filegroup( + name = "tests", + srcs = glob( + [ + "tests/*.py", + "tests/*.json", + ], + ), +) + +filegroup( + name = "all_sources", + srcs = [ + ":sources", + ":tests", + ], + visibility = ["//visibility:public"], +) + +py_library( + name = "score_source_code_linker", + srcs = [":sources"], imports = ["."], visibility = ["//visibility:public"], - deps = ["@score_docs_as_code//src/helper_lib"], + deps = ["//src/helper_lib"], ) py_library( @@ -58,10 +69,10 @@ score_py_pytest( "-s", "-vv", ], - data = glob(["**/*.json"]), + data = glob(["tests/*.json"]), imports = ["."], deps = [ ":score_source_code_linker", - "@score_docs_as_code//src/extensions/score_metamodel", + "//src/extensions/score_metamodel", ], ) diff --git a/src/extensions/score_source_code_linker/__init__.py b/src/extensions/score_source_code_linker/__init__.py index 876e4fccc..c9e57b97d 100644 --- a/src/extensions/score_source_code_linker/__init__.py +++ b/src/extensions/score_source_code_linker/__init__.py @@ -20,6 +20,7 @@ # req-Id: tool_req__docs_dd_link_source_code_link # This whole directory implements the above mentioned tool requirements +import os from collections import defaultdict from copy import deepcopy from pathlib import Path @@ -129,9 +130,15 @@ def build_and_save_combined_file(outdir: Path): Reads the saved partial caches of codelink & testlink Builds the combined JSON cache & saves it """ - source_code_links = load_source_code_links_json( - get_cache_filename(outdir, "score_source_code_linker_cache.json") - ) + source_code_links_json = os.environ.get("SCORE_SOURCELINKS") + if not source_code_links_json: + source_code_links_json = get_cache_filename( + outdir, "score_source_code_linker_cache.json" + ) + else: + source_code_links_json = Path(source_code_links_json) + + source_code_links = load_source_code_links_json(source_code_links_json) test_code_links = load_test_xml_parsed_json( get_cache_filename(outdir, "score_xml_parser_cache.json") ) @@ -171,6 +178,12 @@ def setup_source_code_linker(app: Sphinx, ws_root: Path): }, } + score_sourcelinks_json = os.environ.get("SCORE_SOURCELINKS") + if score_sourcelinks_json: + # No need to generate the JSON file if this env var is set + # because it points to an existing file with the needed data. + return + scl_cache_json = get_cache_filename( app.outdir, "score_source_code_linker_cache.json" ) @@ -195,6 +208,7 @@ def register_test_code_linker(app: Sphinx): def setup_test_code_linker(app: Sphinx, env: BuildEnvironment): + # TODO instead of implementing our own caching here, we should rely on Bazel tl_cache_json = get_cache_filename(app.outdir, "score_xml_parser_cache.json") if ( not tl_cache_json.exists() @@ -244,6 +258,7 @@ def register_combined_linker(app: Sphinx): def setup_combined_linker(app: Sphinx, _: BuildEnvironment): grouped_cache = get_cache_filename(app.outdir, "score_scl_grouped_cache.json") gruped_cache_exists = grouped_cache.exists() + # TODO this cache should be done via Bazel if not gruped_cache_exists or not app.config.skip_rescanning_via_source_code_linker: LOGGER.debug( "Did not find combined json 'score_scl_grouped_cache.json' in _build." diff --git a/src/extensions/score_source_code_linker/needlinks.py b/src/extensions/score_source_code_linker/needlinks.py index c890b13e4..348147292 100644 --- a/src/extensions/score_source_code_linker/needlinks.py +++ b/src/extensions/score_source_code_linker/needlinks.py @@ -13,6 +13,7 @@ # req-Id: tool_req__docs_dd_link_source_code_link import json +import os from dataclasses import asdict, dataclass from pathlib import Path from typing import Any @@ -80,6 +81,12 @@ def store_source_code_links_json(file: Path, needlist: list[NeedLink]): def load_source_code_links_json(file: Path) -> list[NeedLink]: + if not file.is_absolute(): + # use env variable set by Bazel + ws_root = os.environ.get("BUILD_WORKSPACE_DIRECTORY") + if ws_root: + file = Path(ws_root) / file + links: list[NeedLink] = json.loads( file.read_text(encoding="utf-8"), object_hook=needlink_decoder, diff --git a/src/extensions/score_source_code_linker/tests/test_codelink.py b/src/extensions/score_source_code_linker/tests/test_codelink.py index 9e360d1a5..88794c05b 100644 --- a/src/extensions/score_source_code_linker/tests/test_codelink.py +++ b/src/extensions/score_source_code_linker/tests/test_codelink.py @@ -21,9 +21,7 @@ import pytest from attribute_plugin import add_test_properties # type: ignore[import-untyped] -from sphinx_needs.data import NeedsMutable - -from src.extensions.score_metamodel.tests import need as test_need +from sphinx_needs.data import NeedsInfoType, NeedsMutable # Import the module under test # Note: You'll need to adjust these imports based on your actual module structure @@ -56,6 +54,17 @@ """ +def test_need(**kwargs: Any) -> NeedsInfoType: + """Convinience function to create a NeedsInfoType object with some defaults.""" + + kwargs.setdefault("id", "test_need") + kwargs.setdefault("docname", "docname") + kwargs.setdefault("doctype", "rst") + kwargs.setdefault("lineno", "42") + + return NeedsInfoType(**kwargs) + + def encode_comment(s: str) -> str: return s.replace(" ", "-----", 1) diff --git a/src/extensions/score_sphinx_bundle/BUILD b/src/extensions/score_sphinx_bundle/BUILD index 10aa50a31..9145b5ab2 100644 --- a/src/extensions/score_sphinx_bundle/BUILD +++ b/src/extensions/score_sphinx_bundle/BUILD @@ -13,9 +13,15 @@ load("@aspect_rules_py//py:defs.bzl", "py_library") load("@pip_process//:requirements.bzl", "all_requirements") +filegroup( + name = "all_sources", + srcs = glob(["*.py"]), + visibility = ["//visibility:public"], +) + py_library( name = "score_sphinx_bundle", - srcs = ["__init__.py"], + srcs = [":all_sources"], visibility = ["//visibility:public"], deps = all_requirements + [ "@score_docs_as_code//src/extensions:score_plantuml", diff --git a/src/extensions/score_sync_toml/BUILD b/src/extensions/score_sync_toml/BUILD index e9be69268..fdb8acb35 100644 --- a/src/extensions/score_sync_toml/BUILD +++ b/src/extensions/score_sync_toml/BUILD @@ -10,15 +10,22 @@ # # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* + load("@aspect_rules_py//py:defs.bzl", "py_library") load("@pip_process//:requirements.bzl", "requirement") +filegroup( + name = "all_sources", + srcs = glob([ + "*.py", + "*.toml", + ]), + visibility = ["//visibility:public"], +) + py_library( name = "score_sync_toml", - srcs = [ - "__init__.py", - "shared.toml", - ], + srcs = [":all_sources"], imports = ["."], visibility = ["//visibility:public"], deps = [ diff --git a/src/find_runfiles/BUILD b/src/find_runfiles/BUILD index a286c57f2..2112815c4 100644 --- a/src/find_runfiles/BUILD +++ b/src/find_runfiles/BUILD @@ -14,9 +14,15 @@ load("@aspect_rules_py//py:defs.bzl", "py_library") load("@pip_process//:requirements.bzl", "all_requirements") load("@score_tooling//:defs.bzl", "score_py_pytest") +filegroup( + name = "all_sources", + srcs = glob(["*.py"]), + visibility = ["//visibility:public"], +) + py_library( name = "find_runfiles", - srcs = ["__init__.py"], + srcs = [":all_sources"], imports = ["."], visibility = ["//visibility:public"], ) diff --git a/src/helper_lib/BUILD b/src/helper_lib/BUILD index 61d941754..c2c3161f5 100644 --- a/src/helper_lib/BUILD +++ b/src/helper_lib/BUILD @@ -14,12 +14,15 @@ load("@aspect_rules_py//py:defs.bzl", "py_library") load("@pip_process//:requirements.bzl", "all_requirements") load("@score_tooling//:defs.bzl", "score_py_pytest") +filegroup( + name = "all_sources", + srcs = glob(["*.py"]), + visibility = ["//visibility:public"], +) + py_library( name = "helper_lib", - srcs = [ - "__init__.py", - "additional_functions.py", - ], + srcs = [":all_sources"], imports = ["."], visibility = ["//visibility:public"], deps = ["@score_docs_as_code//src/extensions/score_source_code_linker:source_code_linker_helpers"],