diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e9f0100d..c533a221 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -53,10 +53,10 @@ repos: additional_dependencies: - bidict - cairosvg - - capellambse==0.5.69 + - capellambse==0.6.6 - click - jinja2 - - polarion-rest-api-client==1.1.2 + - polarion-rest-api-client==1.1.3 - pydantic - types-requests - types-PyYAML diff --git a/README.md b/README.md index d6cb120d..9c07fa09 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,17 @@ ![image](https://github.com/DSD-DBS/capella-polarion/actions/workflows/lint.yml/badge.svg) ![image](https://github.com/DSD-DBS/capella-polarion/actions/workflows/docs.yml/badge.svg) -Synchronise Capella models with Polarion projects +Synchronise Capella models with Polarion projects. + +![image](c2p-uc1.gif) + +Use cases covered: + +- *Make Capella Objects and attributes of interest available in a Polarion* project so that a Project User could referense those objects and attributes in LiveDocs and WorkItems such as requirements, to ensure consistency across the Project. Model has full authority over the work items that represent model elements. A change to a model element will result in a change to the corresponding WorkItem in Polarion. + +- *Create and maintain LiveDocs* based on a Capella model and a set of templates so that the Project Users could do less paperwork. A change to the model or template shall result in a change to a LiveDoc or related WorkItems. All changes to generated LiveDocs made in Polarion will be over-written by Capella2Polarion as it has "Full Authority" over those documents. + +- *Create and co-maintain LiveDocs* where model would have authority over some sections and people over other sections (mixed-authority) - this would enable Project User to create requirements or other objects in the context of model-derived structure or elements. # Documentation diff --git a/c2p-uc1.GIF b/c2p-uc1.GIF new file mode 100644 index 00000000..55452824 Binary files /dev/null and b/c2p-uc1.GIF differ diff --git a/c2p-uc1.GIF.license b/c2p-uc1.GIF.license new file mode 100644 index 00000000..02c8c230 --- /dev/null +++ b/c2p-uc1.GIF.license @@ -0,0 +1,2 @@ +Copyright DB InfraGO AG and contributors +SPDX-License-Identifier: Apache-2.0 diff --git a/capella2polarion/converters/converter_config.py b/capella2polarion/converters/converter_config.py index ae0d6aae..419b7d5b 100644 --- a/capella2polarion/converters/converter_config.py +++ b/capella2polarion/converters/converter_config.py @@ -9,7 +9,7 @@ from collections import abc as cabc import yaml -from capellambse.model import common, diagram +from capellambse import model as m from capellambse_context_diagrams import filters as context_filters logger = logging.getLogger(__name__) @@ -370,11 +370,11 @@ def _filter_context_diagram_config( def _filter_links( c_type: str, links: list[LinkConfig], is_global: bool = False ) -> list[LinkConfig]: - c_class: type[common.ModelObject | diagram.Diagram] + c_class: type[m.ModelObject] if c_type == "diagram": - c_class = diagram.Diagram + c_class = m.Diagram else: - if not (c_classes := common.find_wrapper(c_type)): + if not (c_classes := m.find_wrapper(c_type)): logger.error("Did not find any matching Wrapper for %r", c_type) return links c_class = c_classes[0] @@ -385,7 +385,7 @@ def _filter_links( is_diagram_elements = capella_attr == DIAGRAM_ELEMENTS_SERIALIZER if ( capella_attr == DESCRIPTION_REFERENCE_SERIALIZER - or (is_diagram_elements and c_class == diagram.Diagram) + or (is_diagram_elements and c_class == m.Diagram) or hasattr(c_class, capella_attr) ): available_links.append(link) diff --git a/capella2polarion/converters/data_session.py b/capella2polarion/converters/data_session.py index 5b9e6282..ef903bda 100644 --- a/capella2polarion/converters/data_session.py +++ b/capella2polarion/converters/data_session.py @@ -5,7 +5,7 @@ import dataclasses -from capellambse.model import common, diagram +from capellambse import model as m from capella2polarion import data_models as dm from capella2polarion.converters import converter_config @@ -17,7 +17,7 @@ class ConverterData: layer: str type_config: converter_config.CapellaTypeConfig - capella_element: diagram.Diagram | common.GenericElement + capella_element: m.ModelElement | m.Diagram work_item: dm.CapellaWorkItem | None = None description_references: list[str] = dataclasses.field(default_factory=list) errors: set[str] = dataclasses.field(default_factory=set) diff --git a/capella2polarion/converters/element_converter.py b/capella2polarion/converters/element_converter.py index 630c2304..94ff6f8d 100644 --- a/capella2polarion/converters/element_converter.py +++ b/capella2polarion/converters/element_converter.py @@ -18,8 +18,7 @@ import markupsafe import polarion_rest_api_client as polarion_api from capellambse import helpers as chelpers -from capellambse.model import common -from capellambse.model import diagram as diag +from capellambse import model as m from lxml import etree from capella2polarion import data_models @@ -156,7 +155,7 @@ def _add_attachment( def _draw_diagram_svg( self, - diagram: capellambse.model.diagram.AbstractDiagram, + diagram: m.AbstractDiagram, file_name: str, title: str, max_width: int, @@ -225,7 +224,7 @@ def __make_href_filter(self, obj: object) -> str | None: def __insert_diagram( self, work_item: data_models.CapellaWorkItem, - diagram: capellambse.model.diagram.AbstractDiagram, + diagram: m.AbstractDiagram, file_name: str, render_params: dict[str, t.Any] | None = None, max_width: int = 800, @@ -262,7 +261,7 @@ def __insert_diagram( def _draw_additional_attributes_diagram( self, work_item: data_models.CapellaWorkItem, - diagram: capellambse.model.diagram.AbstractDiagram, + diagram: m.AbstractDiagram, attribute: str, title: str, render_params: dict[str, t.Any] | None = None, @@ -284,7 +283,7 @@ def _draw_additional_attributes_diagram( } def _sanitize_linked_text( - self, obj: common.GenericElement | diag.Diagram + self, obj: m.ModelElement | m.Diagram ) -> tuple[ list[str], markupsafe.Markup, list[polarion_api.WorkItemAttachment] ]: @@ -301,9 +300,7 @@ def _sanitize_linked_text( return self._sanitize_text(obj, linked_text) def _sanitize_text( - self, - obj: common.GenericElement | diag.Diagram, - text: markupsafe.Markup | str, + self, obj: m.ModelElement | m.Diagram, text: markupsafe.Markup | str ) -> tuple[ list[str], markupsafe.Markup, list[polarion_api.WorkItemAttachment] ]: @@ -393,8 +390,7 @@ def _replace_markup( return match.group(default_group) def _get_requirement_types_text( - self, - obj: common.GenericElement | diag.Diagram, + self, obj: m.ModelElement | m.Diagram ) -> dict[str, dict[str, str]]: type_texts = collections.defaultdict(list) for req in getattr(obj, "requirements", []): @@ -455,7 +451,7 @@ def _diagram( """Serialize a diagram for Polarion.""" diagram = converter_data.capella_element assert converter_data.work_item is not None - assert isinstance(diagram, diag.Diagram) + assert isinstance(diagram, m.Diagram) work_item_id = converter_data.work_item.id diagram_html, attachment = self._draw_diagram_svg( @@ -483,9 +479,9 @@ def _include_pre_and_post_condition( obj = converter_data.capella_element assert hasattr(obj, "precondition"), "Missing PreCondition Attribute" assert hasattr(obj, "postcondition"), "Missing PostCondition Attribute" - assert not isinstance(obj, diag.Diagram) + assert not isinstance(obj, m.Diagram) - def get_condition(cap: common.GenericElement, name: str) -> str: + def get_condition(cap: m.ModelElement, name: str) -> str: if not (condition := getattr(cap, name)): return "" _, value, _ = self._sanitize_linked_text(condition) diff --git a/capella2polarion/converters/link_converter.py b/capella2polarion/converters/link_converter.py index 770b8613..ac2405b6 100644 --- a/capella2polarion/converters/link_converter.py +++ b/capella2polarion/converters/link_converter.py @@ -10,8 +10,7 @@ import capellambse import polarion_rest_api_client as polarion_api -from capellambse.model import common -from capellambse.model import diagram as diag +from capellambse import model as m from capella2polarion import data_models from capella2polarion.connectors import polarion_repo @@ -25,7 +24,7 @@ TYPE_RESOLVERS = {"Part": lambda obj: obj.type.uuid} _Serializer: t.TypeAlias = cabc.Callable[ - [diag.Diagram | common.GenericElement, str, str, dict[str, t.Any]], + [m.ModelElement | m.Diagram, str, str, dict[str, t.Any]], list[polarion_api.WorkItemLink], ] @@ -73,10 +72,10 @@ def create_links_for_work_item( else: refs = _resolve_attribute(obj, link_config.capella_attr) new: cabc.Iterable[str] - if isinstance(refs, common.ElementList): + if isinstance(refs, m.ElementList): new = refs.by_uuid # type: ignore[assignment] elif refs is None: - logger.info( + logger.info( # type: ignore[unreachable] 'For model element %r attribute "%s" is not set', obj._short_repr_(), link_config.capella_attr, @@ -140,7 +139,7 @@ def _get_work_item_ids( def _handle_description_reference_links( self, - obj: common.GenericElement | diag.Diagram, + obj: m.ModelElement | m.Diagram, work_item_id: str, role_id: str, links: dict[str, polarion_api.WorkItemLink], @@ -151,12 +150,12 @@ def _handle_description_reference_links( def _handle_diagram_reference_links( self, - diagram: common.GenericElement | diag.Diagram, + diagram: m.ModelElement | m.Diagram, work_item_id: str, role_id: str, links: dict[str, polarion_api.WorkItemLink], ) -> list[polarion_api.WorkItemLink]: - assert isinstance(diagram, diag.Diagram) + assert isinstance(diagram, m.Diagram) try: refs = set(self._collect_uuids(diagram.nodes)) refs = set(self._get_work_item_ids(work_item_id, refs, role_id)) @@ -173,7 +172,7 @@ def _handle_diagram_reference_links( def _collect_uuids( self, - nodes: cabc.Iterable[common.GenericElement], + nodes: cabc.Iterable[m.ModelElement], ) -> cabc.Iterator[str]: type_resolvers = TYPE_RESOLVERS for node in nodes: @@ -288,9 +287,8 @@ def _create_link_fields( obj._short_repr_(), ) - uuids: cabc.Iterable[str] - if isinstance(attr, common.ElementList): - uuids = attr.by_uuid # type: ignore[assignment] + if isinstance(attr, m.ElementList): + uuids: list[str] = list(attr.by_uuid) else: assert hasattr(attr, "uuid") uuids = [attr.uuid] @@ -385,12 +383,12 @@ def _sorted_unordered_html_list( def _resolve_attribute( - obj: common.GenericElement | diag.Diagram, attr_id: str -) -> common.ElementList[common.GenericElement] | common.GenericElement | None: + obj: m.ModelElement | m.Diagram, attr_id: str +) -> m.ElementList[m.ModelElement] | m.ModelElement: attr_name, _, map_id = attr_id.partition(".") objs = getattr(obj, attr_name) if map_id and objs is not None: - if isinstance(objs, common.GenericElement): + if isinstance(objs, m.ModelElement): return _resolve_attribute(objs, map_id) objs = objs.map(map_id) return objs diff --git a/capella2polarion/converters/polarion_html_helper.py b/capella2polarion/converters/polarion_html_helper.py index ea38acef..e9c10a09 100644 --- a/capella2polarion/converters/polarion_html_helper.py +++ b/capella2polarion/converters/polarion_html_helper.py @@ -6,10 +6,10 @@ import pathlib import re -import capellambse import jinja2 import polarion_rest_api_client as polarion_api from capellambse import helpers as chelpers +from capellambse import model as m from lxml import html wi_id_prefix = "polarion_wiki macro name=module-workitem;params=id=" @@ -93,11 +93,7 @@ def _get_jinja_env(self, template_folder: str | pathlib.Path): def check_model_element( self, obj: object - ) -> ( - capellambse.model.GenericElement - | capellambse.model.diagram.AbstractDiagram - | None - ): + ) -> m.ModelElement | m.AbstractDiagram | None: """Check if a model element was passed. Return None if no element and raise a TypeError if a wrong typed @@ -107,15 +103,9 @@ def check_model_element( if jinja2.is_undefined(obj) or obj is None: return None - if isinstance(obj, capellambse.model.ElementList): + if isinstance(obj, m.ElementList): raise TypeError("Cannot make an href to a list of elements") - if not isinstance( - obj, - ( - capellambse.model.GenericElement, - capellambse.model.diagram.AbstractDiagram, - ), - ): + if not isinstance(obj, (m.ModelElement, m.AbstractDiagram)): raise TypeError(f"Expected a model object, got {obj!r}") return obj diff --git a/docs/source/_static/grouped_linked_work_items.png b/docs/source/_static/grouped_linked_work_items.png new file mode 100644 index 00000000..1d7b4915 Binary files /dev/null and b/docs/source/_static/grouped_linked_work_items.png differ diff --git a/docs/source/_static/grouped_linked_work_items.png.license b/docs/source/_static/grouped_linked_work_items.png.license new file mode 100644 index 00000000..370532fa --- /dev/null +++ b/docs/source/_static/grouped_linked_work_items.png.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Copyright DB InfraGO AG and the capellambse contributors +SPDX-License-Identifier: Apache-2.0 diff --git a/docs/source/_static/linked_work_items.jpeg b/docs/source/_static/linked_work_items.jpeg new file mode 100644 index 00000000..b5bca63d Binary files /dev/null and b/docs/source/_static/linked_work_items.jpeg differ diff --git a/docs/source/_static/linked_work_items.jpeg.license b/docs/source/_static/linked_work_items.jpeg.license new file mode 100644 index 00000000..370532fa --- /dev/null +++ b/docs/source/_static/linked_work_items.jpeg.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Copyright DB InfraGO AG and the capellambse contributors +SPDX-License-Identifier: Apache-2.0 diff --git a/docs/source/_static/mixed-authority-live-doc-divider-down.png b/docs/source/_static/mixed-authority-live-doc-divider-down.png new file mode 100644 index 00000000..2966553f Binary files /dev/null and b/docs/source/_static/mixed-authority-live-doc-divider-down.png differ diff --git a/docs/source/_static/mixed-authority-live-doc-divider-down.png.license b/docs/source/_static/mixed-authority-live-doc-divider-down.png.license new file mode 100644 index 00000000..370532fa --- /dev/null +++ b/docs/source/_static/mixed-authority-live-doc-divider-down.png.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Copyright DB InfraGO AG and the capellambse contributors +SPDX-License-Identifier: Apache-2.0 diff --git a/docs/source/_static/mixed-authority-live-doc-divider-up.png b/docs/source/_static/mixed-authority-live-doc-divider-up.png new file mode 100644 index 00000000..838450d8 Binary files /dev/null and b/docs/source/_static/mixed-authority-live-doc-divider-up.png differ diff --git a/docs/source/_static/mixed-authority-live-doc-divider-up.png.license b/docs/source/_static/mixed-authority-live-doc-divider-up.png.license new file mode 100644 index 00000000..370532fa --- /dev/null +++ b/docs/source/_static/mixed-authority-live-doc-divider-up.png.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Copyright DB InfraGO AG and the capellambse contributors +SPDX-License-Identifier: Apache-2.0 diff --git a/docs/source/conf.py b/docs/source/conf.py index d25c2021..f876a483 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -74,7 +74,15 @@ # -- Options for auto-doc ---------------------------------------------------- autoclass_content = "class" - +autodoc_default_options = { + "members": True, + "undoc-members": True, + # "private-members": True, + # "special-members": True, + # "inherited-members": True, + # "show-inheritance": True, + "noindex": True, +} # -- Options for napoleon ---------------------------------------------------- napoleon_google_docstring = False diff --git a/docs/source/configuration.rst b/docs/source/configuration.rst deleted file mode 100644 index e39ea862..00000000 --- a/docs/source/configuration.rst +++ /dev/null @@ -1,76 +0,0 @@ -.. - Copyright DB InfraGO AG and contributors - SPDX-License-Identifier: Apache-2.0 - -.. _capella2polarion-config: - -YAML -==== -To control the migration of model elements, the following YAML file serves as a -configuration for the capella2polarion service. In this file, you can specify -the layer, class types and attributes for matching Capella model elements. -Additionally you have the control of adding relationships with the links key. -Underneath the links key use attributes on the matched capellambse model -object. Make sure that the attribute name is correct, you can use -`capellambse's documentation`__ for that. - -__ https://dsd-dbs.github.io/py-capellambse/code/capellambse.model.layers.html - -.. literalinclude:: ../../tests/data/model_elements/config.yaml - :language: yaml - :lines: 4- - -The "star" section is a general configuration where you can set links to be -migrated for all class types. For example, ``parent`` and -``description_reference`` are links that will be applied to all specified class -types. Since ``Class`` is a common class type that exists in all layers, links -specific to ``Class`` can be specified here to avoid duplication. This will be -merged into layer specific configuration for ``Class`` if there is any. - -With ``serializer`` you can control which function is called to render the -:py:class:`capella2polarion.data_models.CapellaWorkItem`. There is a generic -serializer including title (name), description and requirement types, taken per -default. You may also define multiple serializers by providing a list of -serializers in the configs. These will be called in the order provided in the -list. Some serializers also support additional configuration. This can be -done by providing a dictionary of serializers with the serializer as key and -the configuration of the serializer as value. If a serializer supports -configuration this will be documented in :ref:`features and roadmap `. - -Sometimes capellambse class types are not the same in Polarion. In order to -handle this case you can use the ``polarion_type`` key to map capellambse types -to the desired Polarion type. For the ``PhysicalComponent`` you can see this in -action, where based on the different permutation of the attributes actor and -nature different Polarion types are used. In capellambse however this is just a -``PhysicalComponent``. Combining this with ``links`` is possible too. You can -configure a generic config and for each specific config you can also add a -``links`` section. Both will be merged. - -Polarion -======== -In general, if an attribute is not configured, it will not be accepted and the -the Rest API will raise a 400 HTTPError since it expects a plain string -attribute. As we use rich text instead, you need to configure -your Polarion project correctly. For that there is the `Polarion DBS Project -Template`_ which includes icon, custom field and enumeration configuration for -a pleasant capella2polarion synchronization. - -.. _Polarion DBS Project Template: https://github.com/DSD-DBS/capella-polarion-template#polarion-dbs-project-template - -In the following are some requirements for the configuration if you don't want -to use the Project Template: - -The matching of diagrams and model elements is done using the ``uuid_capella`` -attribute, which needs to be declared in the ``Custom Fields`` section. Simply -choose ``All Types`` for this attribute. - -To have icons for your model elements, you need to declare the work item type -in the ``workitem-type-enum.xml`` file in the Polarion administration panel and -upload a 16x16 picture file. - -To generate clickable linked work items, you need to configure the link role -enumerations in the ``workitem-link-role-enum.xml`` file. Here, the ID should -match the attributes of the capellambse object (e.g., ``involved_activities``), -or you can define custom attributes that require custom code implementation -(e.g., ``description_reference`` links for references to objects in the -description). diff --git a/docs/source/configuration/polarion.rst b/docs/source/configuration/polarion.rst new file mode 100644 index 00000000..a289a62f --- /dev/null +++ b/docs/source/configuration/polarion.rst @@ -0,0 +1,35 @@ +.. + Copyright DB InfraGO AG and contributors + SPDX-License-Identifier: Apache-2.0 + +.. _polarion-config: + +Polarion +======== +In general, if an attribute is not configured, it will not be accepted and the +the Rest API will raise a 400 HTTPError since it expects a plain string +attribute. As we use rich text instead, you need to configure your Polarion +project correctly. For that there is the `Capella2Polarion Project Template`_ +which includes icon, custom field and enumeration configuration for a pleasant +capella2polarion synchronization. + +.. _Capella2Polarion Project Template: https://github.com/DSD-DBS/capella-polarion-template#polarion-dbs-project-template + +In general it is advised to use a separate Polarion project for the model +synchronization. In the following are some requirements for the configuration +if you don't want to use the Project Template: + +The matching of diagrams and model elements is done using the ``uuid_capella`` +attribute, which needs to be declared in the ``Custom Fields`` section. Simply +choose ``All Types`` for this attribute. + +To have icons for your model elements, you need to declare the work item type +in the ``workitem-type-enum.xml`` file in the Polarion administration panel and +upload a 16x16 picture file. + +To generate clickable linked work items, you need to configure the link role +enumerations in the ``workitem-link-role-enum.xml`` file. Here, the ID should +match the attributes of the capellambse object (e.g., ``involved_activities``), +or you can define custom attributes that require custom code implementation +(e.g., ``description_reference`` links for references to objects in the +description). diff --git a/docs/source/configuration/render_documents.rst b/docs/source/configuration/render_documents.rst new file mode 100644 index 00000000..74a35176 --- /dev/null +++ b/docs/source/configuration/render_documents.rst @@ -0,0 +1,82 @@ +.. + Copyright DB InfraGO AG and contributors + SPDX-License-Identifier: Apache-2.0 + +.. _render-docs-config: + +Live-Docs rendering +=================== +The high-level functionality and use cases are described in the +:ref:`feature ` documentation page. Here it is described how +to set up the Live-Docs rendering. + +Full Authority Mode +******************* +The ``full_authority_config.yaml`` file provides an example configuration for +rendering documents in full authority mode. + +.. literalinclude:: ../../../tests/data/documents/full_authority_config.yaml + :language: yaml + :lines: 4- + +This file describes the Jinja2 template for the rendering, the filename, the +location, the Polarion project ID. This means it is possible to populate +Live-Doc spaces of other projects. A status-allow-list handles the statuses on +which the Live-Doc will be updated on. If the status enum isn't provided in the +list and the Live-Doc status is changed to it, the service won't update the +Live-Doc. This facilitates an efficient and streamlined review and release +process, minimizing disruptions. + +Each instance is a Live-Doc, possibly targeting a specific model element. +With `work_item_layouts` the representational configuration of work items in +the Live-Doc are managed. + +Mixed Authority Mode +******************** +The `mixed_config.yaml` file describes how to set up mixed authority mode +Live-Docs for automated rendering. + +.. literalinclude:: ../../../tests/data/documents/mixed_config.yaml + :language: yaml + :lines: 4- + +.. _mixed-sections-config: + +Under `sections` the individual templates are listed to populate the marked +sections from the Live-Doc. The following macro is used as dividers: + +.. code-block:: html + +
+ #set($statusList = ["draft", "planned", "inReview"]) + #if ($statusList.contains($document.getStatus().id)) +

+ DON'T REMOVE THIS
+ ↓↓↓Below this point all content is autogenerated and will be overwritten↓↓↓ +

+ #end +
+ +This looks then like the following in the Live-Doc: + +.. image:: ../_static/mixed-authority-live-doc-divider-down.png + +Don't forget to do the same for closing the section: + +.. image:: ../_static/mixed-authority-live-doc-divider-up.png + +Configuration File Templates +---------------------------- +The `config.yaml.j2` file in the `documents` folder serves as the primary +configuration template for the Live-Doc rendering service. This Jinja2 template +defines how data from the Capella model should be structured and rendered into +Polarion Live-Docs. + +.. literalinclude:: ../../../tests/data/documents/config.yaml.j2 + :language: jinja + :lines: 4- + +Using this template, the service can populate sections of the Live-Doc with +content based on the selected rendering mode. When working in Mixed authority +mode, the marked sections in the document will be populated, leaving the +unmarked sections untouched. diff --git a/docs/source/configuration/sync.rst b/docs/source/configuration/sync.rst new file mode 100644 index 00000000..5ce31d3b --- /dev/null +++ b/docs/source/configuration/sync.rst @@ -0,0 +1,113 @@ +.. + Copyright DB InfraGO AG and contributors + SPDX-License-Identifier: Apache-2.0 + +.. _sync-config: + +Model synchronization +===================== +To control the migration of model elements, the following YAML file serves as a +configuration for the capella2polarion service. In this file, you can specify +the layer, class types and attributes for matching Capella model elements. +Additionally you have the control of adding relationships with the links key. +Underneath the links key use attributes on the matched capellambse model +object. Make sure that the attribute name is correct, you can use +`capellambse's documentation`__ for that. + +__ https://dsd-dbs.github.io/py-capellambse/code/capellambse.model.layers.html + +Generic +------- + +.. literalinclude:: ../../../tests/data/model_elements/config.yaml + :language: yaml + :lines: 4-26 + +The "star" section is a general configuration where you can set links to be +migrated for all class types. For example, ``parent`` and +``description_reference`` are links that will be applied to all specified class +types. Since ``Class`` is a common class type that exists in all layers, links +specific to ``Class`` can be specified here to avoid duplication. This will be +merged into layer specific configuration for ``Class`` if there is any. + +Serializers +----------- + +.. literalinclude:: ../../../tests/data/model_elements/config.yaml + :language: yaml + :lines: 33-34 + +With ``serializer`` you can control which function is called to render the +:py:class:`capella2polarion.data_models.CapellaWorkItem`. There is a generic +serializer including title (name), description and requirement types, taken per +default. You may also define multiple serializers by providing a list of +serializers in the configs. These will be called in the order provided in the +list. Some serializers also support additional configuration. This can be done +by providing a dictionary of serializers with the serializer as key and the +configuration of the serializer as value. For example ``Class`` using the +``add_tree_diagram`` serializer: + +.. literalinclude:: ../../../tests/data/model_elements/config.yaml + :language: yaml + :lines: 9-13 + +or ``SystemFunction`` with the ``add_context_diagram`` serializer using ``filters``: + +.. literalinclude:: ../../../tests/data/model_elements/config.yaml + :language: yaml + :lines: 64-67 + +If a serializer supports additional parameters this will be documented in the +supported capella serializers table in :ref:`Model synchronization +`. + +Different capella type and polarion type ID +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +.. literalinclude:: ../../../tests/data/model_elements/config.yaml + :language: yaml + :lines: 29-30 + +Sometimes capellambse class types are not the same in Polarion. In order to +handle this case you can use the ``polarion_type`` key to map capellambse types +to the desired Polarion type. + +.. literalinclude:: ../../../tests/data/model_elements/config.yaml + :language: yaml + :lines: 73-91 + +For the ``PhysicalComponent`` you can see this in extreme action, where based +on the different permutation of the attributes actor and nature different +Polarion types are used. In capellambse however this is just a +``PhysicalComponent``. Combining this with ``links`` is possible too. You can +configure a generic config and for each specific config you can also add a +``links`` section. Both will be merged. + +.. _links-config: + +Links +----- +Links can be configured by just providing a list of strings: + +.. literalinclude:: ../../../tests/data/model_elements/config.yaml + :language: yaml + :lines: 33-37 + +However there is a more verbose way that gives you the option to configure the +link further: + +.. literalinclude:: ../../../tests/data/model_elements/config.yaml + :language: yaml + :lines: 52-63 + +The links of ``SystemFunction`` are configured such that a ``polarion_role``, +a separate ``capella_attr``, an ``include``, ``link_field`` and +``reverse_field`` is defined. In this example the ``capella_attr`` is utilizing +the map functionality of capellambse. You can therefore chain attributes using +a ``.`` to get to the desired elements for your link. The ``link_field`` is the +polarion custom field ID for a grouped list of these links. The +``reverse_field`` is the polarion custom field ID for the grouped backlinks of +the links. The ``include`` is an optional feature that renders additional +work item references into the grouped link custom field. In this example for +each linked ``FunctionalExchange`` in the grouped list there will be +``ExchangeItem`` s included. The key "Exchange Items" is used for the +indication in the list. diff --git a/docs/source/features/render_documents.rst b/docs/source/features/render_documents.rst new file mode 100644 index 00000000..eb840979 --- /dev/null +++ b/docs/source/features/render_documents.rst @@ -0,0 +1,53 @@ +.. + Copyright DB InfraGO AG and contributors + SPDX-License-Identifier: Apache-2.0 + +.. _render-documents: + +Render Live-Docs +================ +The `capella2polarion` service supports rendering and updating Polarion Live +Documents in two distinct modes: Full authority and Mixed authority. These +modes control how sections of the Live Document (Live-Doc) are populated and +managed. References to the work items from the model elements synchronization +are resolved automatically. The service is able to populate Live-Doc spaces +completely on its own, managing the complexity of the document layout +configuration for each work item type. The only thing needed for the service is +a dedicated Polarion document space, ``_default`` can be used too. + +The setup and configuration is explained in detail in the :ref:`Live-Docs +rendering ` documentation page. + +Full Authority Mode +******************* +In Full authority mode, the entire Live-Doc is controlled by the +`capella2polarion` service. During each rendering session, the entire document +is re-rendered and updated based on the data provided by the Capella model. Any +manual edits or changes made by a user in Polarion will be overwritten during +the next synchronization process if the status is still set to a value in the +``status_allow_list``. Don't worry comments will persist because everything in +the rendered Live-Doc is a work item. Headings are reused, free text will be +created as a work item of type Text. The status feature enables an efficient +and streamlined review and release process, minimizing disruptions during the +phases. + +It is ensured that the Live-Doc is always consistent with the Capella model and +Polarion project state, but it means that no manual changes can persist between +rendering sessions. + +Mixed Authority Mode +******************** +In mixed authority mode, users have more flexibility over the Live-Doc. Users +can mark specific sections of the Live-Doc via wiki-macro where they would like +content to be inserted or updated by the `capella2polarion` service. If you +want to see how this looks like, have a look in the :ref:`configuration +documentation page `. These sections are populated with +content rendered from Jinja2 templates, while the rest of the document can be +manually managed and updated by users in Polarion. + +This allows users to maintain manual changes in non-synchronized sections of +the document, while still benefiting from automated updates for key sections +filled with model enhanced content. + +If you want to know how to setup the Live-Doc rendering, head to the +:ref:`documentation page `. diff --git a/docs/source/features.rst b/docs/source/features/sync.rst similarity index 56% rename from docs/source/features.rst rename to docs/source/features/sync.rst index b30c6e9e..1c2c2472 100644 --- a/docs/source/features.rst +++ b/docs/source/features/sync.rst @@ -2,23 +2,24 @@ Copyright DB InfraGO AG and contributors SPDX-License-Identifier: Apache-2.0 -.. _features: +.. _sync: -How it works -============ +Model synchronization +===================== The synchronization of Capella objects as Polarion work items is done by using the Polarion REST API. We developed a `Python client`_ where most of the -endpoints are generated from the open API description. In general we serialize +endpoints are generated from the open API description. In general, we serialize all Capella objects fetched from the ``capellambse.MelodyModel`` instance -inferred from the capella2polarion config. Then in order to reduce the request -amount we compare a checksum of the existing work items and the newly created -ones. If the checksum differs a patch request will happen. If there doesn't -exist a work item with a ``capella_uuid`` yet, a new work item will be created. -These custom fields ``_checksum`` and ``_capella_uuid`` are required. -Per default capella2polarion will not delete any work items but set the status -to deleted. With the ``--delete`` flag however you can enable the deletion. +inferred from the capella2polarion config. Then, to reduce the number of +requests, we compare a checksum of the existing work items and the newly +created ones. If the checksum differs, a patch request will happen. If a work +item with a ``capella_uuid`` doesn't exist yet, a new work item will be +created. These custom fields ``_checksum`` and ``_capella_uuid`` are required. +Per default, capella2polarion will not delete any work items but will set the +status to deleted. However, with the ``--delete`` flag, you can enable the +deletion. -.. _Python client: https://github.com/DSD-DBS/capella-polarion-template#polarion-dbs-project-template +.. _Python client: https://github.com/DSD-DBS/polarion-rest-api-client#polarion-rest-api-client Features -------- @@ -29,6 +30,8 @@ Supported Capella types Capella2Polarion lets you synchronize the following attributes through the specific serializer alone: +.. _supported_capella_serializers: + +--------------------------------------+------------------------------------------------------+ | Serializer | Description | +======================================+======================================================+ @@ -36,22 +39,22 @@ specific serializer alone: | | specific serializer. All other serializers are | | | reusing the generic serializer. | | | This serializer populates: type, title, | -| | description, status, uuid_capella amd | +| | description, status, uuid_capella and | | | requirement_types. The requirement type fields | | | are inferred from the requirement type (this is | | | the custom field name/id) and the value is then | | | the requirement's text. | +--------------------------------------+------------------------------------------------------+ -| diagram | A serializer for Capella diagrams. Currently the | +| diagram | A serializer for Capella diagrams. Currently, the | | | diagram is taken from the diagram_cache, served | | | from a GitLab artifact URL and attached as SVG and | | | PNG. | -| | You can provider ``render_params`` in the config and | +| | You can provide ``render_params`` in the config and | | | these will be passed to the render function of | | | capellambse. | +--------------------------------------+------------------------------------------------------+ | include_pre_and_post_condition | A serializer adding post- and precondition | -| | fields. Usually taken for ``Capability`` s. | +| | fields. Usually used for ``Capability`` s. | +--------------------------------------+------------------------------------------------------+ | linked_text_as_description | A serializer resolving ``Constraint`` s and their | | | linked text. | @@ -61,20 +64,36 @@ specific serializer alone: | | The Capella objects where ``context_diagram`` is | | | available can be seen in the `context-diagrams | | | documentation`_. | -| | You can provider ``render_params`` in the config and | +| | You can provide ``render_params`` in the config and | | | these will be passed to the render function of | | | capellambse. | +| | You can provide ``filters`` in the config, and these | +| | will be passed to the render function of capellambse.| +| | See `context-diagrams filters`_ for documentation. | +--------------------------------------+------------------------------------------------------+ | add_tree_view | A serializer adding a tree view diagram to the | | | work item. Same requirements as for | | | ``add_context_diagram``. `Tree View Documentation`_. | -| | You can provider ``render_params`` in the config and | +| | You can provide ``render_params`` in the config and | | | these will be passed to the render function of | | | capellambse. | +| | ``filters`` are available here too. | ++--------------------------------------+------------------------------------------------------+ +| add_jinja_fields | A serializer that allows custom field values to be | +| | filled with rendered Jinja2 template content. This | +| | makes it possible to add complex HTML structures | +| | like tables or lists to the work item as custom | +| | fields. | ++--------------------------------------+------------------------------------------------------+ +| jinja_as_description | A serializer that uses a Jinja2 template to render | +| | the description content of a work item. Similar to | +| | ``add_jinja_fields``, but specifically for the | +| | description field. | +--------------------------------------+------------------------------------------------------+ .. _context-diagrams documentation: https://dsd-dbs.github.io/capellambse-context-diagrams/#context-diagram-extension-for-capellambse .. _Tree View documentation: https://dsd-dbs.github.io/capellambse-context-diagrams/tree_view/ +.. _context-diagrams filters: https://dsd-dbs.github.io/capellambse-context-diagrams/extras/filters/ Links ***** @@ -82,31 +101,32 @@ Links Attributes on Capella objects referencing other Capella objects are rendered as linked work items if (and only if) the link target exists as a work item in Polarion. This needs specific configuration in the work item link roles XML. -If the configuration is done, any attribute can be rendered as a link. +If the configuration is done, any Capella attribute can be rendered as a link. +Per default any configured link will cause the rendering 2 custom fields: + +1. Grouped linked work items +2. Grouped backlink work items (on the link target work items) Grouped linked work items ************************* -In a Polarion live-doc there is no way to filter the linked work items table -which is automatically created from Polarion and can be included into the -document. Therefore Capella2Polarion creates two custom fields for each link -group: A direct field with a list of the links and a field for the reverse -links on each target. - -Roadmap -------- +In a Polarion live-doc, there is no way to filter the linked work items table +which is automatically created from Polarion and can be included in the +document: -We try to work on all issues listed in the `GitHub issues board`_. However in -the nearest future (max. 2 weeks) we want to solve the following problems: +.. image:: ../_static/linked_work_items.jpeg + :width: 700 + :align: center -- Instead of embedding SVGs in the description > attach the SVG and optionally - a PNG. Additonal checksums are made for the work item and each individual - attachment. -- New serializers > support of more Capella types -- Improved logging for CI/CD Pipeline verbosity -- Bug fixes... +Therefore, Capella2Polarion creates two custom fields for each link configured. +The linked work items are then grouped: A direct field with a list of the links +and a field for the reverse links on each target: -It is planned that with the end of April 2024 Capella2Polarion will be -published and available via PyPI. +.. image:: ../_static/grouped_linked_work_items.png + :width: 700 + :align: center -.. _GitHub issues board: https://github.com/DSD-DBS/capella-polarion/issues +For now this feature can not be disabled. Keep in mind that this requires +configuration of 2 new custom fields on the work item type and the targeted +work item type. See the :ref:`linked work items configuration documentation +page ` for more details. diff --git a/docs/source/index.rst b/docs/source/index.rst index 6e8c6f1c..afc78f8a 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -4,42 +4,81 @@ capella2polarion ================ +A tool to migrate Capella content to a Polarion project as work items and to +manage Polarion Live-Documents. -A tool to migrate Capella content to a Polarion project as work items. +Overview +-------- +capella2polarion offers several features to interact with Polarion and Capella +models. Currently, the following features are available: Synchronization of Model-Elements ---------------------------------- - +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Migrate any model element from a ``capellambse.MelodyModel`` to Polarion as a work item. Diagrams are taken from a diagram cache (pipeline artifact from a `capella diagram cache`_) job run to Polarion as work items. The whole folder with the ``index.json`` and the SVGs is needed for the diagram synchronization. -With appropriate :ref:`configuration ` on Polarion and -an according config YAML file for capella2polarion any model element can be -migrated from a Capella model to a Polarion project. For an overview over all -features and supported Capella object types have a look into the :ref:`features -and roadmap ` documentation page. +With appropriate :ref:`configuration ` of the service and on +:ref:`Polarion ` any model element can be migrated from a +Capella model to a Polarion project. For an overview of all features related to +the synchronization and supported Capella object types, have a look at the +:ref:`model synchronization ` documentation page. + +Rendering of Live-Documents +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The `render_documents` command in the CLI allows the rendering of Polarion +Live-Documents in a dedicated documents space inside a Polarion project. This +doesn't need to be the sync project. These documents are generated via +rendering Jinja2 templates, enabling them to be enriched by model data without +requiring the data as a work item in Polarion. + +There are two modes for rendering Live-Documents: + +- **Full Authority Documents**: C2P takes full control over the content, and + any human-made changes to the document will be overwritten in the next + rendering cycle. To make changes persistent, modifications to the Jinja2 + templates are required. + +- **Mixed Authority Documents**: C2P takes control over marked sections of + the document, allowing for collaboration where dedicated model-enhanced + areas coexist with human-edited content. + +Detailed information on the Live-Document rendering feature can be found in the +:ref:`render documents ` documentation page. For a guide on +how this service is configured see the :ref:`configuration page +`. + +.. note:: Additional features will be documented here in the future as they are developed and integrated. .. _capella diagram cache: https://github.com/DSD-DBS/capella-dockerimages/blob/main/ci-templates/gitlab/diagram-cache.yml +.. toctree:: + :maxdepth: 2 + :caption: Features: + + features/render_documents + features/sync + .. toctree:: :maxdepth: 2 :caption: Configuration: - configuration + configuration/render_documents + configuration/sync + configuration/polarion .. toctree:: :maxdepth: 2 - :caption: CI/CD Template: + :caption: CI/CD Templates: pipeline templates/gitlab .. toctree:: :maxdepth: 2 - :caption: Features and Roadmap: + :caption: Roadmap: - features + roadmap .. toctree:: :maxdepth: 3 diff --git a/docs/source/roadmap.rst b/docs/source/roadmap.rst new file mode 100644 index 00000000..4c5fa4f8 --- /dev/null +++ b/docs/source/roadmap.rst @@ -0,0 +1,32 @@ + +.. + Copyright DB InfraGO AG and contributors + SPDX-License-Identifier: Apache-2.0 + +Polarion config diff/mig tool +============================= +The model element synchronization is a service that requires configuration +either in C2P or in Polarion. While doing these synchronizations for multiple +projects, we notice that the effort to maintain the configurations, either +C2P or on Polarion side, increases. Therefore we want to develop an application +that enables Polarion admins to visualize differences of Polarion configuration +files over multiple projects. In the end it should also automate migrations of +updates and changes to the configuration files. + +C2P configuration frontend +========================== +For improving the quality of life for setting up the synchronization of C2P +a nice frontend could automate the generation of the configuration YAML file, +plus a minimal set of configuration XML files needed for Polarion. Before +generation it would be also beneficial to validate the C2P config, on Capella +types, serializers and attributes (links). The latter already happens partially +loading the config. + +Bug-Fixes, issues and requests +============================== +We try to work on all issues listed in the `GitHub issues board`_. Additionally +since C2P is open-source we want to know about the feedback of our external +users. We are curious about the ideas and feature requests you might come up +with ❤️. + +.. _GitHub issues board: https://github.com/DSD-DBS/capella-polarion/issues diff --git a/jupyter-notebooks/document_templates/test-classes.html.j2 b/jupyter-notebooks/document_templates/test-classes.html.j2 index 977fb238..3ab2702d 100644 --- a/jupyter-notebooks/document_templates/test-classes.html.j2 +++ b/jupyter-notebooks/document_templates/test-classes.html.j2 @@ -27,6 +27,6 @@ {{ heading(1, "Class Document", session)}} {{ add_class_dependencies(cls, classes) }} {{ heading(2, "Data Classes", session)}} -{% for cl in classes | unique %} +{% for cl in classes | unique(attribute="uuid") %} {{ insert_work_item(cl, session) }} {% endfor %} diff --git a/jupyter-notebooks/document_templates/test-icd.html.j2 b/jupyter-notebooks/document_templates/test-icd.html.j2 index e1992f0c..2aa43030 100644 --- a/jupyter-notebooks/document_templates/test-icd.html.j2 +++ b/jupyter-notebooks/document_templates/test-icd.html.j2 @@ -76,7 +76,7 @@ This interface control document defines functional interactions between the foll {{ heading(3, "Message Catalog", session)}}

This section identifies messages used within the interface.

{%- set classes = [] %} -{% for ei in interface.exchange_items | unique %} +{% for ei in interface.exchange_items | unique(attribute="uuid") %} {{ insert_work_item(ei, session) }} {% for el in ei.elements %} {{ add_class_dependencies(el.abstract_type, classes) }} @@ -84,6 +84,6 @@ This interface control document defines functional interactions between the foll {% endfor %} {{ heading(3, "Message Description", session)}}

This section provides a detailed description of each message used within the interface.

-{% for cl in classes | unique %} +{% for cl in classes | unique(attribute="uuid") %} {{ insert_work_item(cl, session) }} {% endfor %} diff --git a/pyproject.toml b/pyproject.toml index 96c47c01..38908528 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,11 +28,11 @@ classifiers = [ "Programming Language :: Python :: 3.12", ] dependencies = [ - "capellambse>=0.5.69,<0.6", - "capellambse_context_diagrams>=0.3.1,<0.4", + "capellambse>=0.6.6,<0.7", + "capellambse_context_diagrams>=0.4.0", "click", "PyYAML", - "polarion-rest-api-client==1.1.2", + "polarion-rest-api-client==1.1.3", "bidict", "cairosvg", "jinja2", diff --git a/tests/conftest.py b/tests/conftest.py index 06f2429b..6aa2f427 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -12,6 +12,7 @@ import markupsafe import polarion_rest_api_client as polarion_api import pytest +from capellambse import model as m from capella2polarion import cli, data_models from capella2polarion.connectors import polarion_repo, polarion_worker @@ -83,7 +84,7 @@ def __init__( name: str = "", attribute: t.Any | None = None, ): - super().__init__(spec=capellambse.model.GenericElement) + super().__init__(spec=m.ModelElement) self.uuid = uuid self.name = name self.attribute = attribute diff --git a/tests/test_elements.py b/tests/test_elements.py index d83dfab6..2abbe1b0 100644 --- a/tests/test_elements.py +++ b/tests/test_elements.py @@ -11,7 +11,7 @@ import markupsafe import polarion_rest_api_client as polarion_api import pytest -from capellambse.model import common +from capellambse import model as m from capellambse_context_diagrams import context, filters from capella2polarion import data_models @@ -635,7 +635,7 @@ def test_create_links_from_ElementList(base_object: BaseObjectContainer): obj = FakeModelObject( "uuid6", name="Fake 6", - attribute=common.ElementList( + attribute=m.ElementList( base_object.c2pcli.capella_model, [fake, fake1], FakeModelObject,