From 984aa8676513a9287e91921cdc604c93521e227e Mon Sep 17 00:00:00 2001 From: Maximilian Pollak Date: Tue, 27 May 2025 09:17:50 +0200 Subject: [PATCH] Remove tooling folder Tooling folder is no longer needed as it resides in 'docs-as-code' --- .../score_draw_uml_funcs/__init__.py | 503 ---------------- .../score_draw_uml_funcs/helpers.py | 312 ---------- .../extensions/score_metamodel/metamodel.yaml | 568 ------------------ 3 files changed, 1383 deletions(-) delete mode 100644 docs/_tooling/extensions/score_draw_uml_funcs/__init__.py delete mode 100644 docs/_tooling/extensions/score_draw_uml_funcs/helpers.py delete mode 100644 docs/_tooling/extensions/score_metamodel/metamodel.yaml diff --git a/docs/_tooling/extensions/score_draw_uml_funcs/__init__.py b/docs/_tooling/extensions/score_draw_uml_funcs/__init__.py deleted file mode 100644 index a42859d3bd..0000000000 --- a/docs/_tooling/extensions/score_draw_uml_funcs/__init__.py +++ /dev/null @@ -1,503 +0,0 @@ -# ******************************************************************************* -# Copyright (c) 2025 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 -# ******************************************************************************* -""" -This 'sphinx-extension' is responsible to allow for functional drawings of UML diagrams - - - Features - - Logical Interfaces - - Modules - - Components - - Component Interfaces - -and all applicable linkages between them. - -It provides this functionality by adding classes to `needs_render_context`, -which then can be invoked inside 'needarch' and 'needuml' blocks in rst files. -""" - -import hashlib -import time -from collections.abc import Callable -from functools import cache -from pathlib import Path -from typing import Any - -from sphinx.application import Sphinx -from sphinx_needs.logging import get_logger - -from score_draw_uml_funcs.helpers import ( - gen_header, - gen_interface_element, - gen_link_text, - gen_struct_element, - get_alias, - get_hierarchy_text, - get_impl_comp_from_logic_iface, - get_interface_from_component, - get_interface_from_int, - get_logical_interface_real, - get_module, - get_real_interface_logical, -) - -logger = get_logger(__file__) - - -def setup(app: Sphinx) -> dict[str, object]: - app.config.needs_render_context = draw_uml_function_context - return { - "version": "0.1", - "parallel_read_safe": True, - "parallel_write_safe": True, - } - - -@cache -def scripts_directory_hash(): - start = time.time() - all = "" - for file in Path(".devcontainer/sphinx_conf").glob("**/*.py"): - with open(file) as f: - all += f.read() - hash_object = hashlib.sha256(all.encode("utf-8")) - directory_hash = hash_object.hexdigest() - logger.info( - "calculate directory_hash = " - + directory_hash - + " within " - + str(time.time() - start) - + " seconds." - ) - return directory_hash - - -# ╭──────────────────────────────────────────────────────────────────────────────╮ -# │ Actual drawing functions │ -# ╰──────────────────────────────────────────────────────────────────────────────╯ - - -def draw_comp_incl_impl_int( - need: dict[str, str], - all_needs: dict[str, dict[str, str]], - proc_impl_interfaces: dict[str, str], - proc_used_interfaces: dict[str, list[str]], - white_box_view: bool = False, -) -> tuple[str, str, dict[str, str], dict[str, list[str]]]: - """This function draws a component including any interfaces which are implemented - by the component - - :param dict[str,str] need: Component which should be drawn - :param dict all_needs: Dictionary containing all needs - :param dict[str,dict] proc_impl_interfaces: Dictionary containing all implemented interfaces - which were already processed during this cycle - :param dict[str,dict] proc_used_interfaces: Dictionary containing all used interfaces - which were already processed during this cycle - """ - # Draw outer component - structure_text = f"{gen_struct_element('component', need)} {{\n" - linkage_text = "" - - # Draw inner (sub)components recursively if requested - if white_box_view: - for need_inc in need.get("includes", []): - curr_need = all_needs.get(need_inc, {}) - - # check for misspelled include - if not curr_need: - logger.info(f"{need}: include {need_inc} could not be found") - continue - - if curr_need["type"] != "comp_arc_sta": - continue - - sub_structure, sub_linkage, proc_impl_interfaces, proc_used_interfaces = ( - draw_comp_incl_impl_int( - curr_need, all_needs, proc_impl_interfaces, proc_used_interfaces - ) - ) - - structure_text += sub_structure - linkage_text += sub_linkage - - # close outer component - structure_text += f"}} /' {need['title']} '/ \n\n" - - # Find implemented real interfaces inside the module/component - local_impl_interfaces = get_interface_from_component(need, "implements", all_needs) - local_used_interfaces = get_interface_from_component(need, "uses", all_needs) - - # Add all interfaces which are implemented by component to global list - # and provide implementation - for iface in local_impl_interfaces: - # check for misspelled implements - if not all_needs.get(iface, []): - logger.info(f"{need}: implements {iface} could not be found") - continue - - if not proc_impl_interfaces.get(iface, []): - linkage_text += f"{ - gen_link_text( - need, - '-u->', - all_needs[iface], - 'implements', - ) - } \n" - proc_impl_interfaces[iface] = need["id"] - - # Add all elements which are used by component to global list - for iface in local_used_interfaces: - # check for misspelled used - if not all_needs.get(iface, []): - logger.info(f"{need}: uses {iface} could not be found") - continue - - if not proc_used_interfaces.get(iface, []): - proc_used_interfaces[iface] = [need["id"]] - else: - proc_used_interfaces[iface].append(need["id"]) - - return structure_text, linkage_text, proc_impl_interfaces, proc_used_interfaces - - -def draw_impl_interface( - need: dict[str, str], - all_needs: dict[str, dict[str, str]], - local_impl_interfaces: set[str], -) -> set[str]: - # At First Logical Implemented Interfaces outside the Module - for need_inc in need.get("includes", []): - curr_need = all_needs.get(need_inc, {}) - - # check for misspelled include - if not curr_need: - logger.info(f"{need}: include with id {need_inc} could not be found") - continue - - draw_impl_interface(curr_need, all_needs, local_impl_interfaces) - - # Find implemented logical interface of the components inside the module - local_impl_interfaces.update( - get_interface_from_component(need, "implements", all_needs) - ) - - return local_impl_interfaces - - -def draw_module( - need: dict[str, str], - all_needs: dict[str, dict[str, str]], - proc_impl_interfaces: dict[str, str], - proc_used_interfaces: dict[str, list[str]], -) -> tuple[str, str, dict[str, str], dict[str, list[str]]]: - """ - Drawing and parsing function of a component. - - Example: - input: - need: component_1 - all_needs: all_needs_dict - processed_interfaces: set() - return: - # Part 1 Structure Text - component "Component 1" as C1 { - } - interface "Component Interface 1" as CI1 { - real operation 1 () - real operation 2 () - } - - interface "Logical Interface 1" as LI1 { - Logical Operation 1 - Logical Operation 2 - } - - interface "Component Interface 3" as CI3 { - real operation 5 () - real operation 6 () - } - - # Part 2 Linkage Text - CI1 --> LI1: implements - C1 --> CI1: implements - C1 --> CI3: uses - - # Part 3 processed_interfaces - { - 'real_interface_1', - 'real_interface_2', - 'logical_interface_1' - } - - # Part 4 processed_interfaces - { - 'logical_interface_1', - 'logical_interface_2' - } - - Note: part 1 and 2 are returned as one text item separated by '\n'. - They are interpreted and names are shortened here to aid readability. - Returns: - Tuple of 4 parts. - (Structure Text, Linkage Text, Processed (Real Interfaces), - Processed Logical Interfaces) - """ - linkage_text = "" - structure_text = "" - - # Draw all implemented interfaces outside the boxes - local_impl_interfaces = draw_impl_interface(need, all_needs, set()) - - # Add all interfaces which are implemented by component to global list - # and provide implementation - for iface in local_impl_interfaces: - # check for misspelled implements - if not all_needs.get(iface, []): - logger.info(f"{need}: implements {iface} could not be found") - continue - - if not proc_impl_interfaces.get(iface, []): - structure_text += gen_interface_element(iface, all_needs, True) - - # Draw outer module - structure_text += f"{gen_struct_element('package', need)} {{\n" - - # Draw inner components recursively - for need_inc in need.get("includes", []): - curr_need = all_needs.get(need_inc, {}) - - # check for misspelled include - if not curr_need: - logger.info(f"{need}: include with id {need_inc} could not be found") - continue - - if curr_need["type"] not in ["comp_arc_sta", "mod_view_sta"]: - continue - - sub_structure, sub_linkage, proc_impl_interfaces, proc_used_interfaces = ( - draw_comp_incl_impl_int( - curr_need, all_needs, proc_impl_interfaces, proc_used_interfaces - ) - ) - - structure_text += sub_structure - linkage_text += sub_linkage - - # close outer component - structure_text += f"}} /' {need['title']} '/ \n\n" - - # Add all interfaces which are used by component - for iface, comps in proc_used_interfaces.items(): - if iface not in proc_impl_interfaces: - # Add implementing components and modules - impl_comp_str = get_impl_comp_from_logic_iface(iface, all_needs) - - impl_comp = all_needs.get(impl_comp_str[0], {}) if impl_comp_str else "" - - if impl_comp: - retval = get_hierarchy_text(impl_comp_str[0], all_needs) - structure_text += retval[2] # module open - structure_text += retval[0] # rest open - - structure_text += retval[1] # rest close - structure_text += retval[3] # module close - if iface not in local_impl_interfaces: - structure_text += gen_interface_element(iface, all_needs, True) - - # Draw connection between implementing components and interface - linkage_text += f"{gen_link_text(impl_comp, '-u->', all_needs[iface], 'implements')} \n" - - else: - # Add only interface if component not defined - print(f"{iface}: No implementing component defined") - structure_text += gen_interface_element(iface, all_needs, True) - - # Interface can be used by multiple components - for comp in comps: - # Draw connection between used interfaces and components - linkage_text += f"{gen_link_text(all_needs[comp], '-d[#green]->', all_needs[iface], 'uses')} \n" - - # Remove duplicate links - linkage_text = "\n".join(set(linkage_text.split("\n"))) + "\n" - - return structure_text, linkage_text, proc_impl_interfaces, proc_used_interfaces - - -# ╭──────────────────────────────────────────────────────────────────────────────╮ -# │ Classes with hashing to enable caching │ -# ╰──────────────────────────────────────────────────────────────────────────────╯ - - -class draw_full_feature: - def __repr__(self): - return "draw_full_feature" + " in " + scripts_directory_hash() - - def __call__( - self, need: dict[str, str], all_needs: dict[str, dict[str, str]] - ) -> str: - interfacelist: list[str] = [] - impl_comp: dict[str, str] = dict() - # Store all Elements which have already been processed - proc_impl_interfaces: dict[str, str] = dict() - proc_used_interfaces: dict[str, list[str]] = dict() - proc_modules: list[str] = list() - - link_text = "" - structure_text = ( - f'actor "Feature User" as {get_alias({"id": "Feature_User"})} \n' - ) - - # Define Feature as a package - # structure_text += f"{gen_struct_element('package', need)} {{\n" - - # Add logical Interfaces / Interface Operations (aka includes) - for need_inc in need.get("includes", []): - # Generate list of interfaces since both interfaces - # and interface operations can be included - iface = get_interface_from_int(need_inc, all_needs) - if iface not in interfacelist: - interfacelist.append(iface) - - for iface in interfacelist: - if iface_need := all_needs.get(iface): - if iface: - comps = get_impl_comp_from_logic_iface(iface, all_needs) - - if comps: - impl_comp[iface] = comps[0] - - if imcomp := impl_comp.get(iface, {}): - module = get_module(imcomp, all_needs) - # FIXME: sometimes module is empty, then the following code fails - if not module: - logger.info( - f"FIXME: {need['id']}: Module for interface {iface} -> {imcomp} is empty." - ) - continue - - if module not in proc_modules: - tmp, link_text, proc_impl_interfaces, proc_used_interfaces = ( - draw_module( - all_needs[module], - all_needs, - proc_impl_interfaces, - proc_used_interfaces, - ) - ) - structure_text += tmp - proc_modules.append(module) - - else: - logger.info(f"{need}: Interface {iface} could not be found") - continue - - # Close Package - # structure_text += f"}} /' {need['title']} '/ \n\n" - - for iface in interfacelist: - if imcomp := impl_comp.get(iface): - # Add relation between Actor and Interfaces - link_text += f"{ - gen_link_text( - {'id': 'Feature_User'}, '-d->', all_needs[iface], 'use' - ) - } \n" - - # Add relation between interface and component - if imcomp := impl_comp.get(iface): - link_text += f"{ - gen_link_text( - all_needs[imcomp], - '-u->', - all_needs[iface], - 'implements', - ) - } \n" - else: - logger.info( - f"Interface {iface} is not implemented by any component" - ) - else: - logger.info(f"{need}: Interface {iface} could not be found") - continue - - # Remove duplicate links - link_text = "\n".join(set(link_text.split("\n"))) + "\n" - - return gen_header() + structure_text + link_text - - -class draw_full_module: - def __repr__(self): - return "draw_full_module" + " in " + scripts_directory_hash() - - def __call__( - self, need: dict[str, str], all_needs: dict[str, dict[str, str]] - ) -> str: - # Store all Elements which have already been processed - proc_impl_interfaces: dict[str, str] = dict() - proc_used_interfaces: dict[str, list[str]] = dict() - structure_text, linkage_text, proc_impl_interfaces, proc_used_interfaces = ( - draw_module(need, all_needs, proc_impl_interfaces, proc_used_interfaces) - ) - - return gen_header() + structure_text + linkage_text - - -class draw_full_component: - def __repr__(self): - return "draw_full_component" + " in " + scripts_directory_hash() - - def __call__( - self, need: dict[str, str], all_needs: dict[str, dict[str, str]] - ) -> str: - structure_text, linkage_text, _, _ = draw_comp_incl_impl_int( - need, all_needs, dict(), dict(), True - ) - - # Draw all implemented interfaces outside the boxes - local_impl_interfaces = draw_impl_interface(need, all_needs, set()) - - # Add all interfaces which are implemented by component to global list - # and provide implementation - for iface in local_impl_interfaces: - # check for misspelled implements - if not all_needs.get(iface, []): - logger.info(f"{need}: implements {iface} could not be found") - continue - - structure_text += gen_interface_element(iface, all_needs, True) - - return gen_header() + structure_text + linkage_text - - -class draw_full_interface: - def __repr__(self): - return "draw_full_interface" + " in " + scripts_directory_hash() - - def __call__( - self, need: dict[str, str], all_needs: dict[str, dict[str, str]] - ) -> str: - structure_text = gen_interface_element(need["id"], all_needs, True) - - return structure_text + "\n" - - -CallableType = Callable[[dict[str, Any], dict[str, dict[str, Any]]], str] - -draw_uml_function_context: dict[str, CallableType] = { - "draw_interface": draw_full_interface(), - "draw_module": draw_full_module(), - "draw_component": draw_full_component(), - "draw_feature": draw_full_feature(), -} diff --git a/docs/_tooling/extensions/score_draw_uml_funcs/helpers.py b/docs/_tooling/extensions/score_draw_uml_funcs/helpers.py deleted file mode 100644 index ef59ebbe5c..0000000000 --- a/docs/_tooling/extensions/score_draw_uml_funcs/helpers.py +++ /dev/null @@ -1,312 +0,0 @@ -# ******************************************************************************* -# Copyright (c) 2025 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 -# ******************************************************************************* -from typing import Any - -from sphinx_needs.logging import get_logger - -logger = get_logger(__file__) - - -######################################################################## -# Functions which generate elements -######################################################################## -def gen_format(need: dict[str, str]) -> str: - """Define Layout for Need: - - Set Background Color for Safety Components - - Set Language for component interfaces - """ - - style = "" - - if "comp_arc_sta" in need["type"] and need["safety"] == "ASIL_B": - style = "<>" - - if "real_arc_int" in need["type"]: - style = "" if need["language"] == "rust" else "" - - return style - - -def gen_struct_element(UMLelement: str, need: dict[str, str]) -> str: - """Generate a plantUML element""" - return ( - f'{UMLelement} "{need["title"]}" as {get_alias(need)} ' - f"{gen_format(need)} {get_need_link(need)}" - ) - - -def gen_interface_element( - need_id: str, all_needs: dict[str, dict[str, str]], incl_ops: bool = False -) -> str: - """Generate architectural interface element and - include all operations if selected.""" - - text = f"{gen_struct_element('interface', all_needs[need_id])} {{\n\n" - if incl_ops: - for op in all_needs[need_id].get("included_by_back", []): - raw_text = all_needs[op]["title"] - if raw_text.endswith("()"): - text += f"+ {raw_text} {get_need_link(all_needs[op])}\n" - else: - text += f"+ {raw_text} () {get_need_link(all_needs[op])}\n" - - text += f"\n}} /' {all_needs[need_id]['title']} '/ \n\n" - return text - - -def gen_link_text( - from_need: dict[str, str], link_type: str, to_need: dict[str, str], link_text: str -) -> str: - """ - This function generates a PlantUML link between PlantUML elements - - Example: - input: - from_id: Component Interface 1 - to_id: Logical Interface 1 - link_type: --> - link_text: uses - return: - CI1 --> LI1: uses - - """ - return f"{get_alias(from_need)} {link_type} {get_alias(to_need)}: {link_text}" - - -### Generate PlantUML Headers -def gen_header() -> str: - """Create PlantUML document header""" - return ( - "allow_mixing\n" - + "top to bottom direction\n" - + "hide stereotype\n" - + "hide empty attributes\n" - + gen_sytle_header() - + "\n" - ) - - -def gen_sytle_header() -> str: - """Create PlantUML Header for Style definition""" - return ( - """""" + "\n" - ) - - -######################################################################## -# Functions determine relations between needs -######################################################################## -def get_alias(need: dict[str, str]) -> str: - """Generate a Unique ID for referencing in PlantUML""" - return need["id"] - - -def get_need_link(need: dict[str, str]) -> str: - """Generate the link to the need element from the PlantUML Diagram""" - link = ".." + "/" + need["docname"] + ".html#" + need["id_parent"] - - # Reminder: Link is displayed via triple braces inside a interface - if "int_op" in need["type"]: - return f"[[[{link}]]]" - - return f"[[{link}]]" - - -def get_module(component: str, all_needs: dict[str, dict[str, str]]) -> str: - need = all_needs.get(component, {}) - - if need: - module = need.get("includes_back", "") - - if module: - return module[0] - else: - logger.warning(f"{component}: not defined, misspelled?") - - return "" - - -def get_hierarchy_text( - component: str, all_needs: dict[str, dict[str, str]] -) -> tuple[str, str, str, str]: - """This function determines the corresponding module of any component - - :param str component: component to determine the module - :param dict all_needs: dictionary containing all processed needs - - :return: Tuple of 4 strings: - open_text: Text to place before the component - close_text: Text to place after the component - open_mod_text: Text to open the module - close_mod_text: Text to close the module - """ - need = all_needs[component] - - open_text = "" - close_text = "" - open_mod_text = "" - close_mod_text = "" - parent_need = {} - - if "mod_" not in need["type"]: - parent_need_str = need.get("includes_back", []) - - if parent_need_str: - parent_need = all_needs.get(parent_need_str[0], []) - - if parent_need: - # If Parent Exist and not Module -> Call Function Recursively - retval = get_hierarchy_text(parent_need_str[0], all_needs) - open_text += retval[0] - open_text += f"{gen_struct_element('component', need)} {{\n" - close_text += f"}} /' {need['title']} '/ \n\n" - close_text += retval[1] - open_mod_text = retval[2] - close_mod_text = retval[3] - - else: - # If Top Level Leaf is not a Module - logger.info(f"{need['id']}: not contained in any module") - open_text += f"{gen_struct_element('component', need)} {{\n" - close_text += f"}} /' {need['title']} '/ \n\n" - else: - # Create Module Text - open_mod_text += f"{gen_struct_element('package', need)} {{\n" - close_mod_text += f"}} /' {need['title']} '/ \n\n" - - return open_text, close_text, open_mod_text, close_mod_text - - -def get_interface_from_component( - component: dict[str, str], relation: str, all_needs: dict[str, dict[str, Any]] -) -> list[str]: - """ - Returns a list of interfaces which are related to the component - """ - local_interfaces: list[str] = [] - - for interface in component.get(relation, ""): - iface = get_interface_from_int(interface, all_needs) - if iface not in local_interfaces: - local_interfaces.append(iface) - - return local_interfaces - - -def get_interface_from_int(need_id: str, all_needs: dict[str, dict[str, Any]]) -> str: - """Get Interface for a provided Interface or Interface Operation""" - - int_need = all_needs.get(need_id) - - if not int_need: - logger.warning(f"{need_id}: not defined, misspelled?") - return "" - - if "_int_op" in int_need["type"]: - iface = all_needs[need_id]["included_by"][0] - else: - iface = need_id - - return iface - - -def get_real_interface_logical( - logical_interface_id: str, all_needs: dict[str, dict[str, Any]] -) -> list[str]: - """Get real interface for provided logical interface - The relation is traced via the interface operations - """ - real_ifaces: list[str] = [] - real_ifops: list[str] = [] - logical_ops = all_needs[logical_interface_id]["included_by_back"] - - for logical_op in logical_ops: - real_ifop = all_needs[logical_op].get("implements_back") - if not real_ifop: - logger.info(f"{logical_op}: not implemented by any logical operation") - continue - - real_ifops.extend(real_ifop) if real_ifop not in real_ifops else None - - # Per definition a operation can only be included by one interface - real_iface = all_needs[real_ifop[0]].get("included_by") - - if not real_iface: - logger.info(f"{real_ifop[0]}: not included in any interface") - continue - - real_ifaces.extend(real_iface) if real_iface not in real_ifaces else None - - return real_ifaces - - -def get_logical_interface_real( - real_interface_id: str, all_needs: dict[str, dict[str, Any]] -) -> list[str]: - """Get logical interface based on real interface""" - logical_ifaces: list[str] = list() - - real_ifops = all_needs[real_interface_id].get("included_by_back", []) - - for real_ifop in real_ifops: - logical_ifop = all_needs[real_ifop].get("implements", []) - - if not logical_ifop: - logger.info(f"{real_ifop}: Logical Interface Operation not specified!") - continue - - # One real operation can only implement one logical operation - logical_ifop_need = all_needs.get(logical_ifop[0]) - if not logical_ifop_need: - logger.info( - f"{real_ifop}: Logical Interface Operation Need not defined, probably misspelled!" - ) - continue - - logical_iface = logical_ifop_need.get("included_by", []) - - if not logical_iface: - logger.info(f"{logical_ifop[0]}: Not included by any Logical Interface!") - continue - - logical_ifaces.extend(logical_iface) if logical_iface[ - 0 - ] not in logical_ifaces else logical_ifaces - - return logical_ifaces - - -def get_impl_comp_from_logic_iface( - real_iface: str, all_needs: dict[str, dict[str, str]] -) -> list[str]: - """Get implementing component of the interface""" - implcomp: list[str] = all_needs[real_iface].get("implements_back", []) - - if not implcomp: - logger.info( - f"{all_needs[real_iface]['id']}: Implementing Component not specified!" - ) - - return implcomp - - -def get_use_comp_from_real_iface( - real_iface: str, all_needs: dict[str, dict[str, Any]] -) -> list[str]: - """Get components which use the interface""" - usecomp: list[str] = all_needs[real_iface].get("uses_back", []) - - if usecomp: - logger.info(f"{all_needs[real_iface]}: Interface not used by component!") - - return usecomp diff --git a/docs/_tooling/extensions/score_metamodel/metamodel.yaml b/docs/_tooling/extensions/score_metamodel/metamodel.yaml deleted file mode 100644 index 734619ddb8..0000000000 --- a/docs/_tooling/extensions/score_metamodel/metamodel.yaml +++ /dev/null @@ -1,568 +0,0 @@ -# ******************************************************************************* -# Copyright (c) 2025 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 -# ******************************************************************************* -# yaml-language-server: $schema=./metamodel-schema.json - -needs_types_base_options: - optional_options: - source_code_link: "^https://github.com/eclipse-score/score/blob/.*$" - # Custom semantic validation rules - prohibited_words: - title: - - shall - - must - - will - content: - - just - - about - - really - - some - - thing - - absolutely - -needs_types: - - ############################################################################## - # Process Metamodel - ############################################################################## - # Standards - std_req: - title: "Standard Requirement" - prefix: "std_req__" - mandatory_options: - id: "std_req__(iso26262|isosae21434|isopas8926|aspice_40)__[0-9a-zA-Z_-]*$" - status: "^(valid)$" - optional_links: - links: "^.*$" - - std_wp: - title: "Standard Work Product" - prefix: "std_wp__" - mandatory_options: - id: "std_wp__(iso26262|isosae21434|isopas8926|aspice_40)__[0-9a-z_]*$" - status: "^(valid)$" - # Workflow - workflow: - title: "Workflow" - prefix: "wf__" - mandatory_options: - id: "^wf__[0-9a-z_]*$" - status: "^(valid|draft)$" - mandatory_links: - input: "^wp__.*$" - output: "^wp__.*$" - approved_by: "^rl__.*$" - responsible: "^rl__.*$" - optional_links: - supported_by: "^rl__.*$" - contains: "^gd_(req|temp|chklst|guidl|meth)__.*$" - has: "^doc_(getstrt|concept)__.*$" - # Guidances - gd_req: - title: "Process Requirements" - prefix: "gd_req__" - mandatory_options: - id: "^gd_req__[0-9a-z_]*$" - status: "^(valid|draft)$" - optional_links: - complies: "^std_req__(iso26262|isosae21434|isopas8926|aspice_40)__.*$" - satisfies: "^wf__.*$" - - gd_temp: - title: "Process Template" - prefix: "gd_temp__" - mandatory_options: - id: "^gd_temp__[0-9a-z_]*$" - status: "^(valid|draft)$" - optional_links: - complies: "std_req__(iso26262|isodae21434|isopas8926|aspice_40)__.*$" - - gd_chklst: - title: "Process Checklist" - prefix: "gd_chklst__" - mandatory_options: - id: "^gd_chklst__[0-9a-z_]*$" - status: "^(valid|draft)$" - optional_links: - complies: "std_req__(iso26262|isodae21434|isopas8926|aspice_40)__.*$" - - gd_guidl: - title: "Process Guideline" - prefix: "gd_guidl__" - mandatory_options: - id: "^gd_guidl__[0-9a-z_]*$" - status: "^(valid|draft)$" - optional_links: - complies: "std_req__(iso26262|isosae21434|isopas8926|aspice_40)__.*$" - - gd_method: - title: "Process Method" - prefix: "gd_meth__" - mandatory_options: - id: "^gd_meth__[0-9a-z_]*$" - status: "^(valid|draft)$" - optional_links: - complies: "std_req__(iso26262|isosae21434|isopas8926|aspice_40)__.*$" - # S-CORE Workproduct - workproduct: - title: "Workproduct" - prefix: "wp__" - mandatory_options: - id: "^wp__[0-9a-z_]*$" - status: "^(valid|draft)$" - optional_links: - complies: "std_(wp__iso26262|wp__isosae21434|wp__isopas8926|iic_aspice_40)__.*$" - # Role - role: - title: "Role" - prefix: "rl__" - mandatory_options: - id: "^rl__[0-9a-z_]*$" - optional_links: - contains: "^rl__.*$" - # Documents - doc_concept: - title: "Concept Definition" - prefix: "doc_concept__" - mandatory_options: - id: "^doc_concept__[0-9a-z_]*$" - status: "^(valid|draft)$" - - doc_getstrt: - title: "Getting Startet" - prefix: "doc_getstrt__" - mandatory_options: - id: "^doc_getstrt__[0-9a-z_]*$" - status: "^(valid|draft)$" - - ############################################################################## - # S-CORE Metamodel - ############################################################################## - # General - document: - title: "Generic Document" - prefix: "doc__" - mandatory_options: - id: "^doc__[0-9a-z_]*$" - status: "^(valid|draft|invalid)$" - optional_options: - safety: "^(QM|ASIL_B|ASIL_D)$" - realizes: "^wp__.+$" - # The following 3 guidance requirements enforce the requirement structure and attributes: - # req-Id: gd_req__req__structure - # req-Id: gd_req__requirements_attr_description - # req-Id: gd_req__req__linkage - # Requirements - stkh_req: - title: "Stakeholder Requirement" - prefix: "stkh_req__" - mandatory_options: - id: "^stkh_req__[0-9a-z_]*$" - reqtype: "^(Functional|Interface|Process|Legal|Non-Functional)$" - safety: "^(QM|ASIL_B|ASIL_D)$" - status: "^(valid|invalid)$" - rationale: "^.+$" - optional_options: - security: "^(YES|NO)$" - codelink: "^.*$" - testlink: "^.*$" - reqcovered: "^(YES|NO)$" - testcovered: "^(YES|NO)$" - hash: "^.*$" - - feat_req: - title: "Feature Requirement" - prefix: "feat_req__" - style: "node" - mandatory_options: - id: "^feat_req__[0-9a-z_]*$" - reqtype: "^(Functional|Interface|Process|Legal|Non-Functional)$" - security: "^(YES|NO)$" - safety: "^(QM|ASIL_B|ASIL_D)$" - status: "^(valid|invalid)$" - mandatory_links: - # req-Id: gd_req__req__linkage_fulfill - satisfies: "^stkh_req__.*$" - optional_options: - codelink: "^.*$" - testlink: "^.*$" - reqcovered: "^(YES|NO)$" - testcovered: "^(YES|NO)$" - hash: "^.*$" - - comp_req: - title: "Component Requirement" - prefix: "comp_req__" - mandatory_options: - id: "^comp_req__[0-9a-z_]*$" - reqtype: "^(Functional|Interface|Process|Legal|Non-Functional)$" - security: "^(YES|NO)$" - safety: "^(QM|ASIL_B|ASIL_D)$" - status: "^(valid|invalid)$" - mandatory_links: - satisfies: "^feat_req__.*$" - optional_options: - codelink: "^.*$" - testlink: "^.*$" - reqcovered: "^(YES|NO)$" - testcovered: "^(YES|NO)$" - hash: "^.*$" - - tool_req: - title: "Tool Requirement" - prefix: "tool_req__" - mandatory_options: - id: "^tool_req__[0-9a-z_]*$" - reqtype: "^(Functional|Interface|Process|Legal|Non-Functional)$" - security: "^(YES|NO)$" - safety: "^(QM|ASIL_B|ASIL_D)$" - status: "^(valid|invalid)$" - mandatory_links: - satisfies: "^stkh_req__.*$" - optional_options: - codelink: "^.*$" - testlink: "^.*$" - reqcovered: "^(YES|NO)$" - testcovered: "^(YES|NO)$" - hash: "^.*$" - - aou_req: - title: "Assumption of Use" - prefix: "aou_req__" - mandatory_options: - id: "^aou_req__[0-9a-z_]*$" - reqtype: "^(Functional|Interface|Process|Legal|Non-Functional)$" - security: "^(YES|NO)$" - safety: "^(QM|ASIL_B|ASIL_D)$" - status: "^(valid|invalid)$" - optional_options: - codelink: "^.*$" - testlink: "^.*$" - reqcovered: "^(YES|NO)$" - testcovered: "^(YES|NO)$" - hash: "^.*$" - optional_links: - mitigates: "^.*$" - # Architecture - feat_arc_sta: - title: "Feature Architecture Static View" - prefix: "feat_arc_sta__" - color: "#FEDCD2" - style: "card" - mandatory_options: - id: "^feat_arc_sta__[0-9a-z_]+$" - security: "^(YES|NO)$" - safety: "^(QM|ASIL_B|ASIL_D)$" - status: "^(valid|invalid)$" - mandatory_links: - includes: "^logic_arc_int(_op)*__.+$" - optional_links: - fulfils: "^feat_req__.+$" - - feat_arc_dyn: - title: "Feature Architecture Dynamic View" - prefix: "feat_arc_dyn__" - color: "#FEDCD2" - style: "card" - mandatory_options: - id: "^feat_arc_dyn__[0-9a-z_]+$" - security: "^(YES|NO)$" - safety: "^(QM|ASIL_B|ASIL_D)$" - status: "^(valid|invalid)$" - mandatory_links: - fulfils: "^feat_req__.+$" - - logic_arc_int: - title: "Logical Architecture Interfaces" - prefix: "logic_arc_int__" - color: "#FEDCD2" - style: "card" - mandatory_options: - id: "^logic_arc_int__[0-9a-z_]+$" - security: "^(YES|NO)$" - safety: "^(QM|ASIL_B|ASIL_D)$" - status: "^(valid|invalid)$" - optional_links: - includes: "^logic_arc_int_op__.+$" - fulfils: "^comp_req__.+$" - - logic_arc_int_op: - title: "Logical Architecture Interface Operation" - prefix: "logic_arc_int_op__" - color: "#FEDCD2" - style: "card" - mandatory_options: - id: "^logic_arc_int_op__[0-9a-z_]+$" - security: "^(YES|NO)$" - safety: "^(QM|ASIL_B|ASIL_D)$" - status: "^(valid|invalid)$" - mandatory_links: - included_by: "^logic_arc_int__.+$" - - mod_view_sta: - title: "Module Architecture Static View" - prefix: "mod_view_sta__" - color: "#FEDCD2" - style: "card" - mandatory_options: - id: "^mod_view_sta__[0-9a-z_]+$" - mandatory_links: - includes: "^comp_arc_sta__.+$" - - mod_view_dyn: - title: "Module Architecture Dynamic View" - prefix: "mod_view_dyn__" - color: "#FEDCD2" - style: "card" - mandatory_options: - id: "^mod_view_dyn__[0-9a-z_]+$" - - comp_arc_sta: - title: "Component Architecture Static View" - prefix: "comp_arc_sta__" - color: "#FEDCD2" - style: "card" - mandatory_options: - id: "^comp_arc_sta__[0-9a-z_]+$" - security: "^(YES|NO)$" - safety: "^(QM|ASIL_B|ASIL_D)$" - status: "^(valid|invalid)$" - optional_links: - implements: "^real_arc_int(_op)*__.+$" - includes: "^comp_arc_sta__.+$" - uses: "^real_arc_int(_op)*__.+$" - fulfils: "^comp_req__.+$" - - comp_arc_dyn: - title: "Component Architecture Dynamic View" - prefix: "comp_arc_dyn__" - color: "#FEDCD2" - style: "card" - mandatory_options: - id: "^comp_arc_dyn__[0-9a-z_]+$" - security: "^(YES|NO)$" - safety: "^(QM|ASIL_B|ASIL_D)$" - status: "^(valid|invalid)$" - optional_links: - fulfils: "^comp_req__.+$" - - real_arc_int: - title: "Component Architecture Interfaces" - prefix: "real_arc_int__" - color: "#FEDCD2" - style: "card" - mandatory_options: - id: "^real_arc_int__[0-9a-z_]+$" - security: "^(YES|NO)$" - safety: "^(QM|ASIL_B|ASIL_D)$" - status: "^(valid|invalid)$" - language: "^(cpp|rust)$" - optional_links: - fulfils: "^comp_req__.+$" - - real_arc_int_op: - title: "Component Architecture Interface Operation" - prefix: "real_arc_int_op__" - color: "#FEDCD2" - style: "card" - mandatory_options: - id: "^real_arc_int_op__[0-9a-z_]+$" - security: "^(YES|NO)$" - safety: "^(QM|ASIL_B|ASIL_D)$" - status: "^(valid|invalid)$" - mandatory_links: - included_by: "^real_arc_int__.+$" - optional_links: - implements: "^logic_arc_int_op__.+$" - - - review_header: - prefix: "review__header" - title: "Review Header" - mandatory_options: - id: "^review__header__[0-9a-z_]*$" - reviewers: "^.*$" - approvers: "^.*$" - hash: "^.*$" - template: "^.*$" - - # Implementation - dd_sta: - title: "Static detailed design" - prefix: "dd_sta__" - color: "#FEDCD2" - style: "card" - mandatory_options: - id: "^dd_sta__[0-9a-z_]*$" - security: "^(YES|NO)$" - safety: "^(QM|ASIL_B|ASIL_D)$" - status: "^(valid|invalid)$" - mandatory_links: - implements: "^comp_req__.*$" - satisfies: "^comp_arc_sta__.*$" - optional_links: - includes: "^sw_unit__.*$" - dd_dyn: - title: "Dynamic detailed design" - prefix: "dd_dyn__" - color: "#FEDCD2" - style: "card" - mandatory_options: - id: "^dd_dyn__[0-9a-z_]*$" - security: "^(YES|NO)$" - safety: "^(QM|ASIL_B|ASIL_D)$" - status: "^(valid|invalid)$" - mandatory_links: - implements: "^comp_req__.*$" - satisfies: "^comp_arc_sta__.*$" - sw_unit: - title: "Software unit" - prefix: "sw_unit__" - mandatory_options: - id: "^sw_unit__[0-9a-z_]*$" - security: "^(YES|NO)$" - safety: "^(QM|ASIL_B|ASIL_D)$" - status: "^(valid|invalid)$" - sw_unit_int: - title: "Software unit interfaces" - prefix: "sw_unit_int__" - color: "#FEDCD2" - style: "card" - mandatory_options: - id: "^sw_unit_int__[0-9a-z_]*$" - security: "^(YES|NO)$" - safety: "^(QM|ASIL_B|ASIL_D)$" - status: "^(valid|invalid)$" - -# Extra link types, which shall be available and allow need types to be linked to each other. -# We use a dedicated linked type for each type of a connection, for instance from -# a specification to a requirement. This makes filtering and visualization of such connections -# much easier, as we can sure the target need of a link has always a specific type. -# Docs: https://sphinx-needs.readthedocs.io/en/latest/configuration.html#needs-extra-links -needs_extra_links: - ############################################################## - # Process Metamodel - ############################################################## - # Workflow - contains: - incoming: "contained by" - outgoing: "contains" - - has: - incoming: "relates to" - outgoing: "has" - - input: - incoming: "is input to" - outgoing: "needs input" - - output: - incoming: "is output from" - outgoing: "outputs" - - # Roles - responsible: - incoming: "is responsible for" - outgoing: "responsible" - - approved_by: - incoming: "approves" - outgoing: "approved by" - - supported_by: - incoming: "supports" - outgoing: "supported by" - - # Workproduct - complies: - incoming: "complies to" - outgoing: "complies" - - ############################################################## - # S-CORE Metamodel - ############################################################## - # Requirements - satisfies: - incoming: "satisfied by" - outgoing: "satisfies" - - # Architecture - fulfils: - incoming: "fulfilled by" - outgoing: "fulfils" - - implements: - incoming: "implemented by" - outgoing: "implements" - - uses: - incoming: "used by" - outgoing: "uses" - - includes: - incoming: "included by" - outgoing: "includes" - - included_by: - incoming: "includes" - outgoing: "included by" -############################################################## -# Graph Checks -# The graph checks focus on the relation of the needs and their attributes. -# Checks are defined in the following way: -# check_name: -# needs:defines the needs types to which the check should be applied -# - [include / exclude]: need types to which the check should be applied; -# multiple need types can be defined by separating them with a comma; -# to perform the check on all needs types, set include to "." -# - condition: defines (together with apply) the condition which the needs need to fulfill -# - [and / or / xor / not] -# - check: defines the check that should be applied -# - : defines the relation which is used derive the type of the parent need -# - condition: defines the condition that should be checked -# - [and / or / xor / not] -############################################################## -# req-Id: gd_req__req__linkage_architecture -# req-Id: gd_req__req__linkage_safety -graph_checks: - # req-Id: gd_req__req__linkage_safety - req_safety_linkage: - needs: - include: "comp_req, feat_req" - condition: - and: - - "safety != QM" - - "status == valid" - check: - satisfies: - and: - - "safety != QM" - - "status == valid" - req_linkage: - needs: - include: "comp_req, feat_req" - condition: "status == valid" - check: - satisfies: "status == valid" - # req-Id: gd_req__req__linkage_architecture - arch_safety_linkage: - needs: - include: "comp_req, feat_req" - condition: - and: - - "safety != QM" - - "status == valid" - check: - fulfils: - and: - - "safety != QM" - - "status == valid"