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
3 changes: 3 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ jobs:
- name: Run coverage module tests
run: |
bazel test //coverage/tests:all
- name: Run rules_score tests
run: |
bazel test //bazel/rules/rules_score/...
2 changes: 1 addition & 1 deletion MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -101,5 +101,5 @@ git_override(
remote = "https://github.com/eclipse-score/docs-as-code.git",
)

bazel_dep(name = "score_platform", version = "0.5.0")
# bazel_dep(name = "score_platform", version = "0.5.0")
bazel_dep(name = "score_process", version = "1.3.2")
186 changes: 186 additions & 0 deletions bazel/rules/rules_score/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,141 @@ Builds Sphinx-based HTML documentation from RST source files with support for de
**Output:** ``<name>/html/`` with merged dependency documentation


Artifact Rules
--------------

Artifact rules define S-CORE process work products. All provide ``SphinxSourcesInfo`` for documentation generation.

**feature_requirements**

.. code-block:: python

feature_requirements(
name = "features",
srcs = ["docs/features.rst"],
)

**component_requirements**

.. code-block:: python

component_requirements(
name = "requirements",
srcs = ["docs/requirements.rst"],
)

**assumptions_of_use**

.. code-block:: python

assumptions_of_use(
name = "aous",
srcs = ["docs/assumptions.rst"],
)

**architectural_design**

.. code-block:: python

architectural_design(
name = "architecture",
static = ["docs/static_arch.rst"],
dynamic = ["docs/dynamic_arch.rst"],
)

**safety_analysis**

.. code-block:: python

safety_analysis(
name = "safety",
controlmeasures = ["docs/controls.rst"],
failuremodes = ["docs/failures.rst"],
fta = ["docs/fta.rst"],
arch_design = ":architecture",
)

**dependability_analysis**

.. code-block:: python

dependability_analysis(
name = "analysis",
arch_design = ":architecture",
dfa = ["docs/dfa.rst"],
safety_analysis = [":safety"],
)


Structural Rules
----------------

**unit**

Define the smallest testable software element.

.. code-block:: python

unit(
name = "my_unit",
unit_design = [":architecture"],
implementation = ["//src:lib"],
tests = ["//tests:unit_test"],
)

**component**

Define a collection of units.

.. code-block:: python

component(
name = "my_component",
component_requirements = [":requirements"],
units = [":my_unit"],
implementation = ["//src:binary"],
tests = ["//tests:integration_test"],
)

**dependable_element**

Define a complete SEooC with automatic documentation generation.

.. code-block:: python

dependable_element(
name = "my_seooc",
description = "My safety-critical component",
assumptions_of_use = [":aous"],
requirements = [":requirements"],
architectural_design = [":architecture"],
dependability_analysis = [":analysis"],
components = [":my_component"],
tests = ["//tests:system_test"],
deps = ["@platform//:platform_module"],
)

**Generated Targets:**

- ``<name>``: Sphinx module with HTML documentation
- ``<name>_needs``: Sphinx-needs JSON for cross-referencing
- ``<name>_index``: Generated index.rst with artifact structure

srcs = glob(["docs/**/*.rst"]),
index = "docs/index.rst",
deps = ["@external_module//:docs"],
)

**Key Parameters:**

- ``srcs``: RST/MD source files
- ``index``: Main index.rst file
- ``deps``: Other sphinx_module or dependable_element targets for cross-referencing
- ``sphinx``: Sphinx build binary (default: ``//bazel/rules/rules_score:score_build``)

**Output:** ``<name>/html/`` with merged dependency documentation


Artifact Rules
--------------

Expand Down Expand Up @@ -180,6 +315,14 @@ Define a complete SEooC with automatic documentation generation.
- ``<name>_needs``: Sphinx-needs JSON for cross-referencing
- ``<name>_index``: Generated index.rst with artifact structure

**Implementation Details:**

The macro automatically:

- Generates an index.rst file with a toctree referencing all provided artifacts
- Creates symlinks to artifact files (assumptions of use, requirements, architecture, safety analysis) for co-location with the generated index
- Delegates to ``sphinx_module`` for actual Sphinx build and HTML generation
- Integrates dependencies for cross-module referencing and HTML merging

Dependency Management
---------------------
Expand Down Expand Up @@ -248,6 +391,49 @@ Build:
bazel build //:persistency_kvs
# Output: bazel-bin/persistency_kvs/html/

# Implementation
cc_library(name = "kvs_lib", srcs = ["kvs.cpp"], hdrs = ["kvs.h"])
cc_test(name = "kvs_test", srcs = ["kvs_test.cpp"], deps = [":kvs_lib"])

# Structure
unit(name = "kvs_unit", unit_design = [":arch"],
implementation = [":kvs_lib"], tests = [":kvs_test"])
component(name = "kvs_component", component_requirements = [":reqs"],
units = [":kvs_unit"], implementation = [":kvs_lib"], tests = [])

# SEooC
dependable_element(
name = "persistency_kvs",
description = "Key-Value Store for persistent data storage",
assumptions_of_use = [":aous"],
requirements = [":reqs"],
architectural_design = [":arch"],
dependability_analysis = [":analysis"],
components = [":kvs_component"],
tests = [],
deps = ["@score_process//:score_process_module"],
)

Build:

.. code-block:: bash

bazel build //:kvs_seooc
# Output: bazel-bin/kvs_seooc/html/
# Includes merged HTML from score_platform and score_process modules

Design Rationale
----------------

These rules provide a structured approach to documentation by:

1. **Two-Tier Architecture**: Generic ``sphinx_module`` for flexibility, specialized ``score_component`` for safety-critical work
2. **Dependency Management**: Automatic cross-referencing and HTML merging across modules
3. **Standardization**: SEooC enforces consistent structure for safety documentation
4. **Traceability**: Sphinx-needs integration enables bidirectional traceability
5. **Automation**: Index generation, symlinking, and configuration management are automatic
6. **Build System Integration**: Bazel ensures reproducible, cacheable documentation builds

Reference Implementation
------------------------

Expand Down
21 changes: 6 additions & 15 deletions bazel/rules/rules_score/private/component.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ def _component_impl(ctx):
# Collect implementation targets
implementation_depset = depset(ctx.attr.implementation)

# Collect units and tests
units_depset = depset(ctx.attr.units)
# Collect components and tests
components_depset = depset(ctx.attr.components)
tests_depset = depset(ctx.attr.tests)

# Combine all files for DefaultInfo
Expand All @@ -64,7 +64,7 @@ def _component_impl(ctx):
name = ctx.label.name,
requirements = requirements_depset,
implementation = implementation_depset,
units = units_depset,
components = components_depset,
tests = tests_depset,
),
SphinxSourcesInfo(
Expand All @@ -89,7 +89,7 @@ _component = rule(
doc = "Implementation targets (libraries, binaries) that realize this component",
default = [],
),
"units": attr.label_list(
"components": attr.label_list(
mandatory = True,
doc = "Unit targets that comprise this component",
),
Expand Down Expand Up @@ -149,20 +149,11 @@ def component(
```
"""

# Support both old parameter names and new aliases
final_requirements = requirements
final_units = units if units != None else components

if final_requirements == None:
fail("component() requires 'requirements' parameter")
if final_units == None:
fail("component() requires either 'units' or 'components' parameter")

_component(
name = name,
requirements = final_requirements,
requirements = requirements,
implementation = implementation,
units = final_units,
components = components,
tests = tests,
testonly = testonly,
visibility = visibility,
Expand Down
13 changes: 1 addition & 12 deletions bazel/rules/rules_score/private/component_requirements.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ ComponentRequirementsInfo = provider(
doc = "Provider for component requirements artifacts",
fields = {
"srcs": "Depset of source files containing component requirements",
"requirements": "List of FeatureRequirementsInfo providers this component traces to",
"name": "Name of the component requirements target",
},
)
Expand All @@ -54,15 +55,9 @@ def _component_requirements_impl(ctx):

# Collect feature requirements providers
feature_reqs = []
for feat_req in ctx.attr.feature_requirement:
if FeatureRequirementsInfo in feat_req:
feature_reqs.append(feat_req[FeatureRequirementsInfo])

# Collect transitive sphinx sources from feature requirements
transitive = [srcs]
for feat_req in ctx.attr.feature_requirement:
if SphinxSourcesInfo in feat_req:
transitive.append(feat_req[SphinxSourcesInfo].transitive_srcs)

return [
DefaultInfo(files = srcs),
Expand Down Expand Up @@ -99,7 +94,6 @@ _component_requirements = rule(
def component_requirements(
name,
srcs,
feature_requirement = [],
visibility = None):
"""Define component requirements following S-CORE process guidelines.

Expand All @@ -114,9 +108,6 @@ def component_requirements(
srcs: List of labels to .rst, .md, or .trlc files containing the
component requirements specifications as defined in the S-CORE
process.
feature_requirement: Optional list of labels to feature_requirements
targets that these component requirements trace to. Establishes
bidirectional traceability as defined in the S-CORE process.
visibility: Bazel visibility specification for the generated targets.

Generated Targets:
Expand All @@ -127,13 +118,11 @@ def component_requirements(
component_requirements(
name = "my_component_requirements",
srcs = ["component_requirements.rst"],
feature_requirement = [":my_feature_requirements"],
)
```
"""
_component_requirements(
name = name,
srcs = srcs,
feature_requirement = feature_requirement,
visibility = visibility,
)
Loading