Skip to content
Open
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
11 changes: 11 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ py_library(
"lobster-online-report-nogit.py",
"lobster-python.py",
"lobster-report.py",
"lobster-rst-report.py",
"lobster-trlc.py",
],
visibility = [
Expand All @@ -78,6 +79,7 @@ py_library(
"//lobster/tools/core/online_report",
"//lobster/tools/core/online_report_nogit",
"//lobster/tools/core/report",
"//lobster/tools/core/rst_report",
"//lobster/tools/cpp",
"//lobster/tools/cpptest",
"//lobster/tools/gtest",
Expand Down Expand Up @@ -143,6 +145,15 @@ py_binary(
deps = ["//lobster/tools/core/html_report"],
)

py_binary(
name = "lobster-rst-report",
srcs = ["lobster-rst-report.py"],
visibility = [
"//visibility:public",
],
deps = ["//lobster/tools/core/rst_report"],
)

py_binary(
name = "lobster-json",
srcs = ["lobster-json.py"],
Expand Down
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,19 @@

### 1.0.4-dev


* `lobster-rst-report`:
- New tool: Generate reStructuredText traceability reports for inclusion
in Sphinx documentation projects.
- Supports single-page (`--out`) and multi-page (`--out-dir`) output modes.
- Requires the `sphinx-design` Sphinx extension for dropdown and grid
rendering, and `sphinx.ext.graphviz` for the tracing policy diagram.
- Includes coverage summary table, tracing policy diagram (Graphviz),
issues list, and detailed item cards with cross-references.
- Codebeamer items are rendered as clickable hyperlinks.
- Bazel integration via `subrule_lobster_rst_report` (opt-in).

* Refactored `is_dot_available()` into `lobster.common.graphviz_utils`
(shared between `lobster-html-report` and `lobster-rst-report`).

### 1.0.3

Expand Down
1 change: 1 addition & 0 deletions MODULE.bazel.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ lint-system-tests: style
tests_system/lobster_online_report_nogit \
tests_system/lobster_pkg \
tests_system/lobster_report \
tests_system/lobster_rst_report \
tests_system/lobster_trlc \
tests_system/system_test_case_base.py

Expand Down Expand Up @@ -90,7 +91,8 @@ packages: clean-packages
lobster-json --version && \
lobster-python --version && \
lobster-trlc --version && \
lobster-pkg --version
lobster-pkg --version && \
lobster-rst-report --version

clang-tidy:
cd .. && \
Expand Down
35 changes: 35 additions & 0 deletions bazel/private/lobster_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,41 @@ subrule_lobster_html_report = subrule(
},
)

def _lobster_rst_report_subrule_impl(ctx, lobster_report, _lobster_rst_report):
lobster_rst_report = ctx.actions.declare_file("{}_report.rst".format(ctx.label.name))

# Compute relative path from the RST output back to the workspace root so
# that file references in the report resolve correctly when included in Sphinx.
package = ctx.label.package
package_depth = len(package.split("/")) if package else 0
source_root = "/".join([".." for _ in range(package_depth + 1)]) + "/"

args = ctx.actions.args()
args.add(lobster_report.path)
args.add_all(["--out", lobster_rst_report.path])
args.add_all(["--source-root", source_root])

ctx.actions.run(
executable = _lobster_rst_report,
inputs = [lobster_report],
outputs = [lobster_rst_report],
arguments = [args],
progress_message = "lobster-rst-report {}".format(lobster_rst_report.path),
)

return lobster_rst_report

subrule_lobster_rst_report = subrule(
implementation = _lobster_rst_report_subrule_impl,
attrs = {
"_lobster_rst_report": attr.label(
default = "//:lobster-rst-report",
executable = True,
cfg = "exec",
),
},
)

def _lobster_test_impl(ctx):
lobster_config_substitutions = {}
for input_config in ctx.attr.inputs:
Expand Down
101 changes: 101 additions & 0 deletions documentation/manual-lobster_rst_report.md

@mugdhadhole1 mugdhadhole1 Jun 9, 2026

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.

Can someone generate a visualized report using these rst files?
Should generating html files be part of the rst tool?

Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# lobster-rst-report

Generate reStructuredText (RST) traceability reports from LOBSTER
report files, for inclusion in a Sphinx documentation project.

## Overview

`lobster-rst-report` converts a `.lobster` report file into RST that
can be built by Sphinx. The output uses
[sphinx-design](https://sphinx-design.readthedocs.io/) directives
(dropdowns, grids, cards) for a rich presentation and
[sphinx.ext.graphviz](https://www.sphinx-doc.org/en/master/usage/extensions/graphviz.html)
for the tracing policy diagram.

Two output modes are available:

* **Single-page** (`--out FILE`) — one RST file containing the entire
report.
* **Multi-page** (`--out-dir DIR`) — an `index.rst` plus one RST file
per tracing level, linked via `toctree` directives.

## Installation

`lobster-rst-report` is included in the `bmw-lobster-core` and
`bmw-lobster-monolithic` packages.

Your Sphinx project additionally requires:

```
pip install sphinx-design
```

## Usage

```
lobster-rst-report [LOBSTER_REPORT] [--out FILE | --out-dir DIR] [--source-root PREFIX]
```

| Argument | Description |
|---|---|
| `LOBSTER_REPORT` | Path to the `.lobster` report file (default: `report.lobster`). |
| `--out FILE` | Write a single-page RST report to `FILE` (default: `lobster_report.rst`). |
| `--out-dir DIR` | Write a multi-page RST report to `DIR` (index.rst + one page per level). |
| `--source-root PREFIX` | Prefix prepended to file reference URLs. Use this when the RST output directory differs from the workspace root. |

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.

--source-root is mentioned, but it’s unclear how to choose the value for the final file location.
Maybe adding a concrete example will help the user.


`--out` and `--out-dir` are mutually exclusive.

### Example

```bash
# Generate a multi-page RST report
lobster-rst-report report.lobster --out-dir docs/traceability

# Generate a single-page RST report
lobster-rst-report report.lobster --out docs/traceability.rst
```

## Sphinx project setup

Your Sphinx `conf.py` must load the required extensions:

```python
extensions = ["sphinx_design", "sphinx.ext.graphviz"]
```

For multi-page mode, include the generated `index.rst` via a `toctree`
in your main documentation:

```rst
.. toctree::
:maxdepth: 2
:caption: Traceability

traceability/index
```

### Optional: custom CSS

The generated RST uses the CSS class `lobster-issue-card` for issue
message cards. You can style them in a custom stylesheet:

```css
.lobster-issue-card .sd-card-body {
background-color: #f8d7da;
}
.lobster-issue-card {
border: 2px solid #dc3545;
}
```

## Bazel integration

The tool is available as a Bazel subrule for use in custom rules:

```starlark
load("//:lobster.bzl", "subrule_lobster_rst_report")
```

The subrule accepts a `.lobster` report file and produces a single-page
`.rst` file. It automatically computes `--source-root` based on the
package depth so that file reference links resolve correctly.
2 changes: 1 addition & 1 deletion documentation/user-manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ simplify this. The basic setup is as follows:
2. Annotate traces onto your code, your tests and/or your requirements. Please notice each one of the supported languages has their own way to annotate the tracing tags.
3. Extract the requirement traces with the corresponding lobster conversion tools (e.g. `lobster-cpp`). This converts those traces into a *.lobster file (into a "common unified interchange format").
4. Build report by calling `lobster-report`
5. Render your report by calling the core losbter tools. Usually a local HTML report is desired via `lobster-html-report` or even `lobster-ci-report` for your CI.
5. Render your report by calling the core lobster tools. Usually a local HTML report is desired via `lobster-html-report`, an RST report for Sphinx documentation via `lobster-rst-report`, or even `lobster-ci-report` for your CI.

The basic idea is that you have a number of artefacts that you wish to
relate to each other; stored in different "databases". Sometimes this
Expand Down
25 changes: 25 additions & 0 deletions lobster-rst-report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env python3
#
# LOBSTER - Lightweight Open BMW Software Traceability Evidence Report
# Copyright (C) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License along with this program. If not, see
# <https://www.gnu.org/licenses/>.

import sys

from lobster.tools.core.rst_report.rst_report import main

if __name__ == "__main__":
sys.exit(main())
3 changes: 2 additions & 1 deletion lobster.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ load("//bazel:providers.bzl", _LobsterProvider = "LobsterProvider")
load("//bazel/private:gtest_report.bzl", _gtest_report = "gtest_report", _subrule_gtest_report = "subrule_gtest_report")
load("//bazel/private:lobster_gtest.bzl", _lobster_gtest = "lobster_gtest", _subrule_lobster_gtest = "subrule_lobster_gtest")
load("//bazel/private:lobster_raw.bzl", _lobster_raw = "lobster_raw")
load("//bazel/private:lobster_test.bzl", _lobster_test = "lobster_test", _subrule_lobster_html_report = "subrule_lobster_html_report", _subrule_lobster_report = "subrule_lobster_report")
load("//bazel/private:lobster_test.bzl", _lobster_test = "lobster_test", _subrule_lobster_html_report = "subrule_lobster_html_report", _subrule_lobster_report = "subrule_lobster_report", _subrule_lobster_rst_report = "subrule_lobster_rst_report")
load("//bazel/private:lobster_trlc.bzl", _lobster_trlc = "lobster_trlc", _subrule_lobster_trlc = "subrule_lobster_trlc")

# Re-export LobsterProvider so it can be loaded from this file
Expand All @@ -26,5 +26,6 @@ def lobster_gtest(**kwargs):
subrule_lobster_trlc = _subrule_lobster_trlc
subrule_lobster_gtest = _subrule_lobster_gtest
subrule_lobster_html_report = _subrule_lobster_html_report
subrule_lobster_rst_report = _subrule_lobster_rst_report
subrule_lobster_report = _subrule_lobster_report
subrule_gtest_report = _subrule_gtest_report
1 change: 1 addition & 0 deletions lobster/common/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ py_library(
"exceptions.py",
"file_collector.py",
"file_tag_generator.py",
"graphviz_utils.py",
"io.py",
"items.py",
"level_definition.py",
Expand Down
47 changes: 47 additions & 0 deletions lobster/common/graphviz_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env python3
#
# LOBSTER - Lightweight Open BMW Software Traceability Evidence Report
# Copyright (C) 2025 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
"""Shared Graphviz utilities for LOBSTER report tools."""

import subprocess
from typing import Optional


def is_dot_available(dot: Optional[str] = None) -> bool:
"""Return True if the ``dot`` executable (Graphviz) is on PATH.

Args:
dot: Optional explicit path to the ``dot`` binary. When ``None``
(default) the system PATH is searched.

Returns:
``True`` if Graphviz ``dot`` is available, ``False`` otherwise.
"""
try:
subprocess.run(
[dot if dot else "dot", "-V"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
encoding="UTF-8",
check=True,
timeout=5,
)
return True
except (FileNotFoundError, subprocess.TimeoutExpired,
subprocess.CalledProcessError):
return False
7 changes: 4 additions & 3 deletions lobster/requirements.rsl
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,11 @@ enum Tools {
// tools that consume the output of other LOBSTER tools
lobster_online_report
lobster_html_report
lobster_rst_report
}

type UseCase {
description '''
description '''
The text of the use case.
The format shall be : As a < role > I want < description of the UseCase >
A use case shall describe the goal that the user wants to achieve by using LOBSTER.
Expand All @@ -86,7 +87,7 @@ type UseCase {

enum Impact_Type {
Safety
'''
'''
The potential error has a safety impact.
'''
Financial
Expand All @@ -102,7 +103,7 @@ type PotentialError {
This shall be a description of a potential error that may occur in a tool.
''' String
impacts String [1..*]
affects
affects
'''List of use cases which the potential error could affect'''
UseCase[1..*]
impact_type Impact_Type
Expand Down
13 changes: 1 addition & 12 deletions lobster/tools/core/html_report/html_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,25 +39,14 @@
Requirement, Implementation,
Activity)
from lobster.common.meta_data_tool_base import MetaDataToolBase
from lobster.common.graphviz_utils import is_dot_available
from lobster.tools.core.html_report.html_report_css import CSS
from lobster.tools.core.html_report.html_report_js import JAVA_SCRIPT


LOBSTER_GH = "https://github.com/bmw-software-engineering/lobster"


def is_dot_available(dot):
try:
subprocess.run([dot if dot else "dot", "-V"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
encoding="UTF-8",
check=True)
return True
except FileNotFoundError:
return False


def name_hash(name):
hobj = hashlib.md5()
hobj.update(name.encode("UTF-8"))
Expand Down
Loading
Loading