Score Source Code Linker#

A Sphinx extension for enabling source code and test traceability for requirements. This extension integrates with Bazel and sphinx-needs to automatically generate traceability links between implementation, tests, and documentation.


Overview#

The feature is split into two layers:

  1. Bazel pre-processing (before Sphinx runs) Generates and aggregates JSON caches containing the raw source_code_link findings (and, if available, repository metadata like repo_name/hash/url).

  2. Sphinx extension (during the Sphinx build) Reads the aggregated JSON, validates and adapts it, and finally injects the links into Sphinx needs in the final layout (RepoSourceLink).

This separation makes combo builds faster and more deterministic, because the expensive repository scanning/parsing happens outside the Sphinx process.


How It Works#


Source Code Linker Extension#

1a. Reads the merged JSON produced by Bazel 1b. Reads test.xml files and generates testlinks JSON 2. Validates and adapts both JSON cache files 3. Merges and converts them into the final structure: RepoSourceLink

Test Tagging Options#

# Import the decorator
from attribute_plugin import add_test_properties

# Add the decorator to your test
@add_test_properties(
    partially_verifies=["tool_req__docs_common_attr_title", "tool_req__docs_common_attr_description"],
    test_type="interface-test",
    derivation_technique="boundary-values"
)
def test_feature():
    """
    Mandatory docstring that contains a description of the test
    """
    ...

Note: If you use the decorator, it will check that you have specified a docstring inside the function.

Data Flow#

  1. XML Parsing (xml_parser.py)

    • Scans bazel-testlogs/ or tests-report for test.xml files.

    • Parses test cases and extracts:

      • Name & Classname

      • File path

      • Line

      • Result (e.g. passed, failed, skipped)

      • Result text (if failed/skipped will check if message was attached to it)

      • Verifications (PartiallyVerifies, FullyVerifies)

    • Also parses metadata according to the metadata rules

    • Cases without metadata are logged out as info (not errors).

    • Test cases with metadata are converted into:

      • DataFromTestCase (used for external needs)

      • DataForTestLink (used for linking tests to requirements)

If there is a Classname then it gets combined with the function name for the displayed link as follows: Classname__Functionname

  1. Need Linking

    • Generates external Sphinx needs from DataFromTestCase.

    • Creates testlink attributes on linked requirements.

    • Warns on missing need IDs.

Example JSON Cache (DataFromTestCase)#

The DataFromTestCase depicts the information gathered about one testcase.

[
  {
    "name": "test_cache_file_with_encoded_comments",
    "file": "src/extensions/score_source_code_linker/tests/test_codelink.py",
    "line": "340",
    "result": "passed",
    "TestType": "interface-test",
    "DerivationTechnique": "boundary-values",
    "result_text": "",
    "PartiallyVerifies": "tool_req__docs_common_attr_title, tool_req__docs_common_attr_description",
    "FullyVerifies": null
    "repo_name": "local_module",
    "hash": "",
    "url": "",
  }
]

Combined JSON Example#

[
  {
    "need": "tool_req__docs_common_attr_title",
    "links": {
      "CodeLinks": [
        {
          "file": "src/extensions/score_metamodel/metamodel.yaml",
          "line": 33,
          "tag": "#--req-Id:",# added `--` to avoid detection
          "need": "tool_req__docs_common_attr_title",
          "full_line": "#--req-Id: tool_req__docs_common_attr_title", # added `--` to avoid detection
          "repo_name": "local_module",
          "hash": "",
          "url": "",

        }
      ],
      "TestLinks": [
        {
          "name": "test_cache_file_with_encoded_comments",
          "file": "src/extensions/score_source_code_linker/tests/test_codelink.py",
          "line": 340,
          "need": "tool_req__docs_common_attr_title",
          "verify_type": "partially",
          "result": "passed",
          "result_text": "",
          "repo_name": "local_module",
          "hash": "",
          "url": "",
        }
      ]
    }
  }
]


Known Limitations#

General#

  • In combo builds, known_good_json is required.

  • inefficiencies in creating the links and saving the JSON caches

  • Not compatible with Esbonio/Live_preview

Codelinks#

  • GitHub links may 404 if the commit isn’t pushed

  • Tags must match exactly (e.g. # req-Id)

  • source_code_link isn’t visible until the full Sphinx build is completed


High-level Data Flow Summary#

  1. Bazel Script #1: scan + parse → write per-repo cache (includes repo metadata if known)

  2. Bazel Script #2: merge caches → write single merged JSON

  3. Sphinx Extension: read merged JSON → adapt to RepoSourceLink → inject source_code_link and testlink into needs


Clearing Cache Manually#

To clear the build cache, run:

rm -rf _build/

Internal Overview#

The bazel part:

scripts_bazel/
├── BUILD   # Declare libraries and filegroups needed for bazel
├── generate_sourcelinks_cli.py # Bazel step 1 => Parses sourcefiles for tags
├── merge_sourcelinks.py
└── tests
│   └── ...

The Sphinx extension

score_source_code_linker/
├── __init__.py                   # Main Sphinx extension; combines CodeLinks + TestLinks
├── generate_source_code_links_json.py  # Most functionality moved to 'scripts_bazel/generate_sourcelinks_cli'
├── need_source_links.py         # Data model for combined links
├── repo_source_links.py         # Data model for Repo combined links (Final output JSON)
├── helpers.py                   # Misc. functions used throughout SCL
├── needlinks.py                 # CodeLink dataclass & JSON encoder/decoder
├── testlink.py                  # DataForTestLink definition & logic
├── xml_parser.py                # Parses XML files into test case data
├── tests/                       # Testsuite, containing unit & integration tests
│   └── ...

Clearing Cache Manually#

To clear the build cache, run:

rm -rf _build/

Examples:#

To see working examples for CodeLinks & TestLinks, take a look at the Docs-As-Code documentation.

Example CodeLink Example CodeLink

Example TestLink