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
16 changes: 9 additions & 7 deletions bzl/bundle_rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -384,10 +384,12 @@ def _docs_bundle_impl(ctx):

child_source_files = []
child_external_runfiles = []
sourcelinks = [
struct(file = source_link, repository = ctx.label.workspace_name)
for source_link in ctx.files.sourcelinks
]
sourcelinks = []
if ctx.file.sourcelinks_json:
sourcelinks.append(struct(
file = ctx.file.sourcelinks_json,
repository = ctx.label.workspace_name,
))
for index, child in enumerate(ctx.attr.bundles):
entries.extend([
_rebase_bundle_entry(
Expand Down Expand Up @@ -432,7 +434,7 @@ _docs_bundle = rule(
attrs = {
"source_dir_globbed": attr.label_list(allow_files = True),
"source_targets": attr.label_list(allow_files = True),
"sourcelinks": attr.label_list(allow_files = True),
"sourcelinks_json": attr.label(allow_single_file = True),
"strip_prefix": attr.string(default = ""),
"entry_doc": attr.string(default = "index"),
"bundles": attr.label_list(providers = [DocsBundleInfo]),
Expand All @@ -448,7 +450,7 @@ def create_bundle(
bundles,
source_dir_globbed = [],
source_targets = [],
sourcelinks = [],
sourcelinks_json = None,
strip_prefix = "",
entry_doc = "index",
data = [],
Expand All @@ -464,7 +466,7 @@ def create_bundle(
name = name,
source_dir_globbed = source_dir_globbed,
source_targets = source_targets,
sourcelinks = sourcelinks,
sourcelinks_json = sourcelinks_json,
strip_prefix = strip_prefix,
entry_doc = entry_doc,
bundles = [bundle.bundle for bundle in parsed_bundles],
Expand Down
56 changes: 8 additions & 48 deletions docs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ def _module_name_without_prefix():
return ""
return module_name.split("_", 1)[-1]

def _bundle_internal_target(name, target):
"""Return the conventional name for a target internal to a bundle."""
return name + ".__internal__." + target

def _generated_conf_impl(ctx):
output = ctx.actions.declare_file(ctx.attr.output_path)
ctx.actions.expand_template(
Expand Down Expand Up @@ -121,7 +125,6 @@ def _declare_docs_bundle(
data = [],
entry_doc = "index",
bundles = [],
scan_code = [],
code_targets = [],
visibility = None,
**kwargs):
Expand Down Expand Up @@ -155,8 +158,6 @@ def _declare_docs_bundle(
"mount_at": <where it shall me mounted>,
"attach_to": <optional document to attach the bundle to; for a bundle root it defaults to the mount_at parent's index>
}.
scan_code: Deprecated. Explicit source files or filegroups to scan for
source-code links. Use `code_targets` for implementation targets.
code_targets: Implementation targets or filegroups to scan for source-code
links. Implementation target source files and their dependencies
are collected recursively; filegroups expand to their files.
Expand All @@ -169,22 +170,15 @@ def _declare_docs_bundle(
("docs_bundle(%s): srcs cannot be combined with source_dir; " +
"put generated sources in a dedicated bundle") % name,
)

# Keep directory-discovered sources separate from explicit Bazel targets so
# each kind can retain its own runtime path and staging behavior.
source_dir_globbed = glob_doc_sources(source_dir) if source_dir != None else []
sourcelinks = []
if scan_code:
print("WARNING: docs_bundle(%s) uses deprecated scan_code; use code_targets instead." % name)
sourcelinks_name = name + "_sourcelinks_json"
_sourcelinks_json(name = sourcelinks_name, srcs = scan_code)
sourcelinks = [":" + sourcelinks_name]
sourcelinks_json = None
if code_targets:
code_targets_sourcelinks = generate_code_target_sourcelinks(
name = name + "_code_targets_sourcelinks_json",
sourcelinks_json = generate_code_target_sourcelinks(
name = _bundle_internal_target(name, "sourcelinks_json"),
code_targets = code_targets,
)
sourcelinks.append(code_targets_sourcelinks)

# Store the source directory relative to the workspace so bundle consumers
# can locate the original files without copying them.
Expand All @@ -208,7 +202,7 @@ def _declare_docs_bundle(
name = name,
source_dir_globbed = source_dir_globbed,
source_targets = srcs,
sourcelinks = sourcelinks,
sourcelinks_json = sourcelinks_json,
strip_prefix = strip_prefix,
entry_doc = entry_doc,
bundles = bundles,
Expand All @@ -224,7 +218,6 @@ def docs_bundle(
data = [],
entry_doc = "index",
bundles = [],
scan_code = [],
code_targets = [],
visibility = None,
**kwargs):
Expand All @@ -242,7 +235,6 @@ def docs_bundle(
data = data,
entry_doc = entry_doc,
bundles = bundles,
scan_code = scan_code,
code_targets = code_targets,
visibility = visibility,
**kwargs
Expand Down Expand Up @@ -290,7 +282,6 @@ def docs(
data = [],
deps = [],
external_needs = [],
scan_code = [],
code_targets = [],
test_sources = [],
known_good = None,
Expand All @@ -312,8 +303,6 @@ def docs(
files.
deps: Additional dependencies for the documentation build.
external_needs: List of external needs targets to include in the documentation build.
scan_code: Deprecated. Explicit source files or filegroups to scan for source
code links. Use `code_targets` for implementation targets.
code_targets: Implementation targets or filegroups to scan for source code
links. Implementation targets are scanned recursively; filegroups
expand to their files.
Expand Down Expand Up @@ -423,7 +412,6 @@ def docs(
data = data,
entry_doc = "index",
bundles = bundles,
scan_code = scan_code,
code_targets = code_targets,
visibility = ["//visibility:public"],
tags = ["manual"]
Expand Down Expand Up @@ -598,31 +586,3 @@ def docs(
actual = Label("//scripts_bazel:traceability_gate"),
tags = ["manual"],
)

def _sourcelinks_json(name, srcs):
"""
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.
"""
output_file = name + ".json"

generate_sourcelinks_tool = Label("//scripts_bazel:generate_sourcelinks")

native.genrule(
name = name,
srcs = srcs,
outs = [output_file],
cmd = """
$(location {generate_sourcelinks_tool}) \
--output $@ \
$(SRCS)
""".format(generate_sourcelinks_tool = generate_sourcelinks_tool),
tools = [generate_sourcelinks_tool],
visibility = ["//visibility:public"],
tags = ["manual"],
)
4 changes: 0 additions & 4 deletions docs/how-to/source_to_doc_links.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,3 @@ uses. You may also pass filegroups; their files are scanned directly.
source_dir = "docs",
code_targets = [":some_application"],
)

The older ``scan_code`` parameter remains available for existing configurations
that explicitly provide files or filegroups, but it is deprecated. Prefer
``code_targets`` for new configurations.
10 changes: 1 addition & 9 deletions docs/reference/bazel_macros.rst
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,6 @@ Minimal example (root ``BUILD``)
generated JSON is supplied to ``live_preview`` just like a normal documentation
build.

- ``scan_code`` (list of Bazel labels, deprecated)
Explicit source files or filegroups to scan. Use ``code_targets`` for
implementation targets; it follows their dependencies automatically.

- ``external_needs`` (list of bazel labels)
External ``:needs_json_file`` targets from other modules/repositories
for referencing their needs.
Expand Down Expand Up @@ -169,7 +165,7 @@ site).
visibility = ["//visibility:public"],
)

Signature: ``docs_bundle(name, source_dir = None, srcs = [], data = [], entry_doc = "index", bundles = [], scan_code = [], code_targets = [], visibility = None)``.
Signature: ``docs_bundle(name, source_dir = None, srcs = [], data = [], entry_doc = "index", bundles = [], code_targets = [], visibility = None)``.

- ``source_dir`` (string, optional)
Directory holding the bundle's own doc sources. It is globbed the same way as
Expand Down Expand Up @@ -230,10 +226,6 @@ Signature: ``docs_bundle(name, source_dir = None, srcs = [], data = [], entry_do
owns one cached scan result; Bazel only regenerates it when its collected source
inputs change.

- ``scan_code`` (list of Bazel labels, deprecated)
Explicit source files or filegroups to scan. Prefer ``code_targets`` for
implementation targets.

Edge cases
----------

Expand Down
2 changes: 0 additions & 2 deletions src/extensions/docs/source_code_linker.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ The Bazel parts are responsible for producing the **intermediate caches** that t
Each `docs_bundle` scans the source files selected by its `code_targets`
attribute. A *per bundle JSON cache* is then generated and saved; Bazel
reuses it until its source inputs change.
`scan_code` remains available for explicit files or filegroups, but is
deprecated.
This script `scripts_bazel/generate_sourcelinks_cli.py` finds all codelinks per file, and gathers them into
one JSON cache per repository.
It also adds metadata to each needlink that is needed in further steps.
Expand Down
4 changes: 4 additions & 0 deletions src/tests/docs_bzl/scenarios/reference_integration/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ load("//:docs.bzl", "docs")
# The reference integration combines platform feature requirements and two
# software modules into one documentation site, just like the real S-CORE
# integration. Each module's bundle contains its component documentation.
# Each component also scans an annotated implementation file through
# ``code_targets``. The integration test verifies that those source links
# survive the component -> module -> site bundle composition and are rendered
# on the mounted component pages.
# The component packages live below the module's ``docs`` source directory,
# matching the feature-package layout used by the real S-CORE integration.
#
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ docs(
project = "S-CORE Legacy Module",
project_url = "https://example.invalid/score-legacy-module",
source_dir = "docs",
test_sources = ["src/tests/docs_bzl/scenarios/reference_integration"],
data = [
"//src/tests/docs_bzl/scenarios/reference_integration/score_platform:needs_json",
"@score_process_description//:needs_json",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,23 @@

load("//:docs.bzl", "docs")

filegroup(
name = "component_sources",
srcs = ["implementation.py"],
)

# Keep the component as a complete documentation producer while placing its
# Bazel package below the module's source directory. This mirrors the feature
# package layout used by the S-CORE integration and exercises package-aware
# source ownership at runtime.
# source ownership at runtime. The implementation file is deliberately
# supplied through ``code_targets`` so its traceability annotation exercises
# the source-link generation path used by real component targets.
docs(
project = "S-CORE Legacy Component",
project_url = "https://example.invalid/score-legacy-component",
source_dir = ".",
data = [
"//src/tests/docs_bzl/scenarios/reference_integration/score_platform:needs_json",
],
code_targets = [":component_sources"],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# *******************************************************************************
# 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
# *******************************************************************************

# req-traceability: tool_req__legacy_component


def legacy_component_value():
"""Return a value from the legacy component implementation."""
return "legacy"
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,11 @@ S-CORE Legacy Component

This component consumes platform feature requirements through the legacy
``data`` API and is mounted by the legacy module.

.. tool_req:: Legacy component implementation is traceable
:id: tool_req__legacy_component
:version: 1

The legacy component implementation is covered by the component source
code-link scan. The integration test checks that this link is preserved
when the component is built alone, by its module, and by the full site.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ docs(
project = "S-CORE Modern Module",
project_url = "https://example.invalid/score-modern-module",
source_dir = "docs",
test_sources = ["src/tests/docs_bzl/scenarios/reference_integration"],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work as just a folder not a bazel target?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test_sources is a list of repo-relative paths. I was not even aware we have test_sources

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just checked, it has 0 users. Next candidate for removal.

external_needs = [
"//src/tests/docs_bzl/scenarios/reference_integration/score_platform:needs_json",
"@score_process_description//:needs_json",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,22 @@

load("//:docs.bzl", "docs")

filegroup(
name = "component_sources",
srcs = ["implementation.py"],
)

# This component is a nested documentation package, like the feature bundles
# in the S-CORE integration. Its parent module owns the surrounding source
# tree and mounts this bundle at the component placement.
# tree and mounts this bundle at the component placement. The implementation
# file is supplied through ``code_targets`` to exercise source-link generation
# for a component that is propagated through the module bundle.
docs(
project = "S-CORE Modern Component",
project_url = "https://example.invalid/score-modern-component",
source_dir = ".",
external_needs = [
"//src/tests/docs_bzl/scenarios/reference_integration/score_platform:needs_json",
],
code_targets = [":component_sources"],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# *******************************************************************************
# 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
# *******************************************************************************


def modern_component_value():
"""Return a value from the modern component implementation."""
# req-traceability: tool_req__modern_component
return "modern"
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,11 @@ S-CORE Modern Component

This component consumes platform feature requirements through the current
``external_needs`` API and is mounted by the modern module.

.. tool_req:: Modern component implementation is traceable
:id: tool_req__modern_component
:version: 1

The modern component implementation is covered by the component source
code-link scan. The integration test checks that this link is preserved
when the component is built alone, by its module, and by the full site.
Loading
Loading