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
5 changes: 4 additions & 1 deletion BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************

load("@aspect_rules_py//py:defs.bzl", "py_library")
load("@score_tooling//:defs.bzl", "cli_helper", "copyright_checker")
load("//:docs.bzl", "docs")

Expand All @@ -33,6 +32,10 @@ docs(
data = [
"@score_process//:needs_json",
],
scan_code = [
"//scripts_bazel:sources",
"//src:all_sources",
],
source_dir = "docs",
)

Expand Down
2 changes: 1 addition & 1 deletion MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
95 changes: 84 additions & 11 deletions docs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************

"""
Easy streamlined way for S-CORE docs-as-code.
"""

# Multiple approaches are available to build the same documentation output:
#
# 1. **Esbonio via IDE support (`ide_support` target)**:
Expand All @@ -37,12 +41,10 @@
#
# For user-facing documentation, refer to `/README.md`.

load("@aspect_rules_py//py:defs.bzl", "py_binary", "py_library")
load("@pip_process//:requirements.bzl", "all_requirements", "requirement")
load("@aspect_rules_py//py:defs.bzl", "py_binary")
load("@pip_process//:requirements.bzl", "all_requirements")
load("@rules_pkg//pkg:mappings.bzl", "pkg_files", "strip_prefix")
load("@rules_pkg//pkg:tar.bzl", "pkg_tar")
load("@rules_python//sphinxdocs:sphinx.bzl", "sphinx_build_binary", "sphinx_docs")
load("@rules_python//sphinxdocs:sphinx_docs_library.bzl", "sphinx_docs_library")
load("@score_tooling//:defs.bzl", "score_virtualenv")

def _rewrite_needs_json_to_docs_sources(labels):
Expand All @@ -56,10 +58,47 @@ def _rewrite_needs_json_to_docs_sources(labels):
out.append(s)
return out

def docs(source_dir = "docs", data = [], deps = []):
def _rewrite_needs_json_to_sourcelinks(labels):
"""Replace '@repo//:needs_json' -> '@repo//:sourcelinks_json' for every item."""
out = []
for x in labels:
s = str(x)
if s.endswith("//:needs_json"):
out.append(s.replace("//:needs_json", "//:sourcelinks_json"))
else:
out.append(s)
return out

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 @score_docs_as_code//scripts_bazel:merge_sourcelinks) \
--output $@ \
$(SRCS)
""",
tools = ["@score_docs_as_code//scripts_bazel:merge_sourcelinks"],
)

def docs(source_dir = "docs", data = [], deps = [], scan_code = []):
"""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.
scan_code: List of code targets to scan for source code links.
"""

call_path = native.package_name()
Expand Down Expand Up @@ -100,70 +139,79 @@ def docs(source_dir = "docs", data = [], deps = []):
visibility = ["//visibility:public"],
)

_sourcelinks_json(name = "sourcelinks_json", srcs = scan_code)

data_with_docs_sources = _rewrite_needs_json_to_docs_sources(data)
additional_combo_sourcelinks = _rewrite_needs_json_to_sourcelinks(data)
_merge_sourcelinks(name = "merged_sourcelinks", sourcelinks = [":sourcelinks_json"] + additional_combo_sourcelinks)

py_binary(
name = "docs",
tags = ["cli_help=Build documentation:\nbazel run //:docs"],
srcs = ["@score_docs_as_code//src:incremental.py"],
data = data,
data = data + [":sourcelinks_json"],
deps = deps,
env = {
"SOURCE_DIRECTORY": source_dir,
"DATA": str(data),
"ACTION": "incremental",
"SCORE_SOURCELINKS": "$(location :sourcelinks_json)",
},
)

py_binary(
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)",
},
)

py_binary(
name = "docs_check",
tags = ["cli_help=Verify documentation:\nbazel run //:docs_check"],
srcs = ["@score_docs_as_code//src:incremental.py"],
data = data,
data = data + [":sourcelinks_json"],
deps = deps,
env = {
"SOURCE_DIRECTORY": source_dir,
"DATA": str(data),
"ACTION": "check",
"SCORE_SOURCELINKS": "$(location :sourcelinks_json)",
},
)

py_binary(
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 + [":sourcelinks_json"],
deps = deps,
env = {
"SOURCE_DIRECTORY": source_dir,
"DATA": str(data),
"ACTION": "live_preview",
"SCORE_SOURCELINKS": "$(location :sourcelinks_json)",
},
)

py_binary(
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)",
},
)

Expand Down Expand Up @@ -193,3 +241,28 @@ def docs(source_dir = "docs", data = [], deps = []):
tools = data,
visibility = ["//visibility:public"],
)

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"

native.genrule(
name = name,
srcs = srcs,
outs = [output_file],
cmd = """
$(location @score_docs_as_code//scripts_bazel:generate_sourcelinks) \
--output $@ \
$(SRCS)
""",
tools = ["@score_docs_as_code//scripts_bazel:generate_sourcelinks"],
visibility = ["//visibility:public"],
)
41 changes: 41 additions & 0 deletions docs/concepts/docs_deps.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

.. _docs_dependencies:

==========================
Docs Dependencies
==========================

When running ``bazel run :docs``, the documentation build system orchestrates multiple interconnected dependencies to produce HTML documentation.

1. Gather inputs (Bazel may do this parallelized):

* Extract source code links from files via ``sourcelinks_json`` rule.

* Optionally, merge source links using the ``merge_sourcelinks`` rule.

* Needs (requirements) are gathered from various ``needs_json`` targets specified in the ``data`` attribute.

2. Documentation sources are read from the specified source directory (default: ``docs/``).
Sphinx processes the documentation sources along with the merged data to generate the final HTML output.

.. plantuml::

@startuml
left to right direction

collections "Documentation Sources" as DocsSource
collections "Needs JSON Targets" as NeedsTargets
collections "Source Code Links" as SourceLinks
artifact "Merge Data" as Merge
process "Sphinx Processing" as Sphinx
artifact "HTML Output" as HTMLOutput
collections "S-CORE extensions" as SCoreExt

DocsSource --> Sphinx
NeedsTargets --> Sphinx
SCoreExt --> Sphinx
SourceLinks --> Merge
Merge --> Sphinx
Sphinx --> HTMLOutput

@enduml
1 change: 1 addition & 0 deletions docs/concepts/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ Here you find explanations how and why docs-as-code works the way it does.
:maxdepth: 1

bidirectional_traceability
docs_deps
46 changes: 41 additions & 5 deletions docs/how-to/source_to_doc_links.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,50 @@ 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.
Finally, pass the scan results to the ``docs`` rule as ``scan_code`` attribute.

.. code-block:: starlark
:emphasize-lines: 15
:linenos:

filegroup(
name = "some_sources",
srcs = [
"foo.py",
"bar.cpp",
"data.yaml",
] + glob(["subdir/**/.py"]),
)

docs(
data = [
"@score_process//:needs_json",
],
source_dir = "docs",
scan_code = [":some_sources"],
)
3 changes: 3 additions & 0 deletions scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Scripts

The scripts directory is only for local development (linters) so far.
38 changes: 38 additions & 0 deletions scripts_bazel/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# *******************************************************************************
# 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")

filegroup(
name = "sources",
srcs = glob(["**/*.py"]),
visibility = ["//visibility:public"],
)

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"],
)
3 changes: 3 additions & 0 deletions scripts_bazel/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Scripts Bazel

This folder contains executables to be used within Bazel rules.
Loading
Loading