From 3c2950db3f5af9ff57f8a097e39048211ef52e3e Mon Sep 17 00:00:00 2001 From: ewuerger Date: Wed, 21 Aug 2024 12:36:32 +0200 Subject: [PATCH] refactor: Add prefixes in `ConverterConfig` Instead of adding them during the serialization --- capella2polarion/__main__.py | 13 ++- .../converters/converter_config.py | 80 +++++++++++-------- .../converters/element_converter.py | 7 -- capella2polarion/converters/link_converter.py | 6 +- .../converters/model_converter.py | 3 - ci-templates/gitlab/synchronise_elements.yml | 6 +- tests/test_elements.py | 13 +-- 7 files changed, 66 insertions(+), 62 deletions(-) diff --git a/capella2polarion/__main__.py b/capella2polarion/__main__.py index 8f924768..2b0231ee 100644 --- a/capella2polarion/__main__.py +++ b/capella2polarion/__main__.py @@ -38,6 +38,8 @@ @click.option("--polarion-pat", envvar="POLARION_PAT", type=str) @click.option("--polarion-delete-work-items", is_flag=True, default=False) @click.option("--capella-model", type=cli_helpers.ModelCLI(), default=None) +@click.option("--type-prefix", type=str, default="") +@click.option("--role-prefix", type=str, default="") @click.pass_context def cli( ctx: click.core.Context, @@ -47,6 +49,8 @@ def cli( polarion_pat: str, polarion_delete_work_items: bool, capella_model: capellambse.MelodyModel, + type_prefix: str, + role_prefix: str, ) -> None: """Synchronise data from Capella to Polarion.""" if capella_model.diagram_cache is None: @@ -59,6 +63,8 @@ def cli( polarion_pat, polarion_delete_work_items, capella_model, + type_prefix=type_prefix, + role_prefix=role_prefix, ) capella2polarion_cli.setup_logger() ctx.obj = capella2polarion_cli @@ -79,15 +85,11 @@ def print_cli_state(capella2polarion_cli: Capella2PolarionCli) -> None: default=None, ) @click.option("--force-update", is_flag=True, default=False) -@click.option("--type-prefix", type=str, default="") -@click.option("--role-prefix", type=str, default="") @click.pass_context def synchronize( ctx: click.core.Context, force_update: bool, synchronize_config: typing.TextIO, - type_prefix: str, - role_prefix: str, ) -> None: """Synchronise model elements.""" capella_to_polarion_cli: Capella2PolarionCli = ctx.obj @@ -97,13 +99,10 @@ def synchronize( ) capella_to_polarion_cli.load_synchronize_config(synchronize_config) capella_to_polarion_cli.force_update = force_update - capella_to_polarion_cli.type_prefix = type_prefix - capella_to_polarion_cli.role_prefix = role_prefix converter = model_converter.ModelConverter( capella_to_polarion_cli.capella_model, capella_to_polarion_cli.polarion_params.project_id, - type_prefix=capella_to_polarion_cli.type_prefix, role_prefix=capella_to_polarion_cli.role_prefix, ) diff --git a/capella2polarion/converters/converter_config.py b/capella2polarion/converters/converter_config.py index d81ab52c..57ef7766 100644 --- a/capella2polarion/converters/converter_config.py +++ b/capella2polarion/converters/converter_config.py @@ -63,7 +63,10 @@ def _default_type_conversion(c_type: str) -> str: class ConverterConfig: """The overall Config for capella2polarion.""" - def __init__(self): + def __init__(self, type_prefix: str = "", role_prefix: str = ""): + self.type_prefix = type_prefix + self.role_prefix = role_prefix + self._layer_configs: dict[str, dict[str, list[CapellaTypeConfig]]] = {} self._global_configs: dict[str, CapellaTypeConfig] = {} self.polarion_types = set[str]() @@ -77,7 +80,7 @@ def read_config_file(self, synchronize_config: t.TextIO): global_config_dict = config_dict.pop("*", {}) all_type_config = global_config_dict.pop("*", {}) global_links = all_type_config.get("links", []) - self.__global_config.links = _force_link_config(global_links) + self.__global_config.links = self._force_link_config(global_links) if "Diagram" in global_config_dict: diagram_config = global_config_dict.pop("Diagram") or {} @@ -122,21 +125,21 @@ def set_layer_config( # As we set up all types this way, we can expect that all # non-compliant links are coming from global context here closest_links = _filter_links(c_type, closest_config.links, True) - p_type = ( - type_config.get("polarion_type") - or closest_config.p_type - or _default_type_conversion(c_type) + p_type = add_prefix( + ( + type_config.get("polarion_type") + or closest_config.p_type + or _default_type_conversion(c_type) + ), + self.type_prefix, ) self.polarion_types.add(p_type) + links = self._force_link_config(type_config.get("links", [])) self._layer_configs[layer][c_type].append( CapellaTypeConfig( p_type, type_config.get("serializer") or closest_config.converters, - _filter_links( - c_type, - _force_link_config(type_config.get("links", [])), - ) - + closest_links, + _filter_links(c_type, links) + closest_links, type_config.get("is_actor", _C2P_DEFAULT), type_config.get("nature", _C2P_DEFAULT), ) @@ -152,7 +155,7 @@ def set_global_config(self, c_type: str, type_config: dict[str, t.Any]): p_type, type_config.get("serializer"), _filter_links( - c_type, _force_link_config(type_config.get("links", [])) + c_type, self._force_link_config(type_config.get("links", [])) ) + self._get_global_links(c_type), type_config.get("is_actor", _C2P_DEFAULT), @@ -165,14 +168,39 @@ def set_diagram_config(self, diagram_config: dict[str, t.Any]): p_type = diagram_config.get("polarion_type") or "diagram" self.polarion_types.add(p_type) links = _filter_links( - c_type, _force_link_config(diagram_config.get("links", [])) + c_type, self._force_link_config(diagram_config.get("links", [])) ) self.diagram_config = CapellaTypeConfig( - p_type, + add_prefix(p_type, self.type_prefix), diagram_config.get("serializer") or "diagram", links + self._get_global_links(c_type), ) + def _force_link_config(self, links: t.Any) -> list[LinkConfig]: + result: list[LinkConfig] = [] + for link in links: + if isinstance(link, str): + config = LinkConfig( + capella_attr=link, + polarion_role=add_prefix(link, self.role_prefix), + ) + elif isinstance(link, dict): + config = LinkConfig( + capella_attr=(lid := link["capella_attr"]), + polarion_role=add_prefix( + link.get("polarion_role", lid), self.role_prefix + ), + include=link.get("include", {}), + ) + else: + logger.error( + "Link not configured correctly: %r", + link, + ) + continue + result.append(config) + return result + def get_type_config( self, layer: str, c_type: str, **attributes: t.Any ) -> CapellaTypeConfig | None: @@ -252,25 +280,11 @@ def _force_dict( raise TypeError("Unsupported Type") -def _force_link_config(links: t.Any) -> list[LinkConfig]: - result: list[LinkConfig] = [] - for link in links: - if isinstance(link, str): - config = LinkConfig(capella_attr=link, polarion_role=link) - elif isinstance(link, dict): - config = LinkConfig( - capella_attr=(lid := link["capella_attr"]), - polarion_role=link.get("polarion_role", lid), - include=link.get("include", {}), - ) - else: - logger.error( - "Link not configured correctly: %r", - link, - ) - continue - result.append(config) - return result +def add_prefix(polarion_type: str, prefix: str) -> str: + """Add a prefix to the given ``polarion_type``.""" + if prefix: + return f"{prefix}_{polarion_type}" + return polarion_type def _filter_links( diff --git a/capella2polarion/converters/element_converter.py b/capella2polarion/converters/element_converter.py index 99c04000..fdf1662b 100644 --- a/capella2polarion/converters/element_converter.py +++ b/capella2polarion/converters/element_converter.py @@ -85,13 +85,11 @@ def __init__( capella_polarion_mapping: polarion_repo.PolarionDataRepository, converter_session: data_session.ConverterSession, generate_attachments: bool, - type_prefix: str = "", ): self.model = model self.capella_polarion_mapping = capella_polarion_mapping self.converter_session = converter_session self.generate_attachments = generate_attachments - self.type_prefix = type_prefix self.jinja_envs: dict[str, jinja2.Environment] = {} def serialize_all(self) -> list[data_models.CapellaWorkItem]: @@ -125,11 +123,6 @@ def serialize(self, uuid: str) -> data_models.CapellaWorkItem | None: ) converter_data.work_item = None - if self.type_prefix and converter_data.work_item is not None: - converter_data.work_item.type = ( - f"{self.type_prefix}_{converter_data.work_item.type}" - ) - if converter_data.errors: log_args = ( converter_data.capella_element._short_repr_(), diff --git a/capella2polarion/converters/link_converter.py b/capella2polarion/converters/link_converter.py index 2632edb5..a7932247 100644 --- a/capella2polarion/converters/link_converter.py +++ b/capella2polarion/converters/link_converter.py @@ -63,8 +63,6 @@ def create_links_for_work_item( for link_config in converter_data.type_config.links: serializer = self.serializers.get(link_config.capella_attr) role_id = link_config.polarion_role - if self.role_prefix: - role_id = f"{self.role_prefix}_{role_id}" try: if serializer: new_links.extend( @@ -225,13 +223,13 @@ def create_grouped_link_fields( key = link.secondary_work_item_id back_links.setdefault(key, []).append(link) - role_id = self._remove_prefix(role) config: converter_config.LinkConfig | None = None for link_config in data.type_config.links: - if link_config.polarion_role == role_id: + if link_config.polarion_role == role: config = link_config break + role_id = self._remove_prefix(role) self._create_link_fields( work_item, role_id, grouped_links, config=config ) diff --git a/capella2polarion/converters/model_converter.py b/capella2polarion/converters/model_converter.py index bc25897c..35bf1828 100644 --- a/capella2polarion/converters/model_converter.py +++ b/capella2polarion/converters/model_converter.py @@ -29,12 +29,10 @@ def __init__( self, model: capellambse.MelodyModel, project_id: str, - type_prefix: str = "", role_prefix: str = "", ): self.model = model self.project_id = project_id - self.type_prefix = type_prefix self.role_prefix = role_prefix self.converter_session: data_session.ConverterSession = {} @@ -110,7 +108,6 @@ def generate_work_items( polarion_data_repo, self.converter_session, generate_attachments, - self.type_prefix, ) work_items = serializer.serialize_all() for work_item in work_items: diff --git a/ci-templates/gitlab/synchronise_elements.yml b/ci-templates/gitlab/synchronise_elements.yml index 7d58264f..e2299051 100644 --- a/ci-templates/gitlab/synchronise_elements.yml +++ b/ci-templates/gitlab/synchronise_elements.yml @@ -17,8 +17,8 @@ capella2polarion_synchronise_elements: $([[ $CAPELLA2POLARION_DEBUG -eq 1 ]] && echo '--debug') \ --polarion-project-id=${CAPELLA2POLARION_PROJECT_ID:?} \ --capella-model="${CAPELLA2POLARION_MODEL_JSON:?}" \ + ${CAPELLA2POLARION_TYPE_PREFIX:+--type-prefix="$CAPELLA2POLARION_TYPE_PREFIX"} \ + ${CAPELLA2POLARION_ROLE_PREFIX:+--role-prefix="$CAPELLA2POLARION_ROLE_PREFIX"} \ synchronize \ --synchronize-config=${CAPELLA2POLARION_CONFIG:?} \ - $([[ $CAPELLA2POLARION_FORCE_UPDATE -eq 1 ]] && echo '--force-update') \ - ${CAPELLA2POLARION_TYPE_PREFIX:+--type-prefix="$CAPELLA2POLARION_TYPE_PREFIX"} \ - ${CAPELLA2POLARION_ROLE_PREFIX:+--role-prefix="$CAPELLA2POLARION_ROLE_PREFIX"} + $([[ $CAPELLA2POLARION_FORCE_UPDATE -eq 1 ]] && echo '--force-update') diff --git a/tests/test_elements.py b/tests/test_elements.py index f3e48604..113e79e0 100644 --- a/tests/test_elements.py +++ b/tests/test_elements.py @@ -718,8 +718,10 @@ def test_create_link_from_single_attribute_with_role_prefix( ) base_object.pw.polarion_data_repo.update_work_items([work_item_2]) - base_object.mc.converter_session["uuid2"].work_item = work_item_2 - + converter_data = base_object.mc.converter_session["uuid2"] + converter_data.work_item = work_item_2 + link_config = converter_data.type_config.links[0] + link_config.polarion_role = f"_C2P_{link_config.polarion_role}" expected = polarion_api.WorkItemLink( "Obj-2", "Obj-1", @@ -733,6 +735,7 @@ def test_create_link_from_single_attribute_with_role_prefix( base_object.c2pcli.capella_model, role_prefix="_C2P", ) + links = link_serializer.create_links_for_work_item("uuid2") assert links == [expected] @@ -1725,7 +1728,7 @@ def test_add_jinja_to_description(self, model: capellambse.MelodyModel): def test_multiple_serializers(model: capellambse.MelodyModel, prefix: str): cap = model.by_uuid(TEST_OCAP_UUID) type_config = converter_config.CapellaTypeConfig( - "test", + f"{prefix}_test" if prefix else "test", ["include_pre_and_post_condition", "add_context_diagram"], [], ) @@ -1738,12 +1741,12 @@ def test_multiple_serializers(model: capellambse.MelodyModel, prefix: str): ) }, True, - prefix, ) work_item = serializer.serialize(TEST_OCAP_UUID) assert work_item is not None + assert work_item.type is not None assert work_item.type.startswith(prefix) assert "preCondition" in work_item.additional_attributes assert "postCondition" in work_item.additional_attributes @@ -1810,13 +1813,13 @@ def test_generic_work_item_with_type_prefix( } type_config = config.get_type_config(layer, c_type, **attributes) assert type_config is not None + type_config.p_type = f"{prefix}_{type_config.p_type}" ework_item = data_models.CapellaWorkItem(id=f"{prefix}_TEST") serializer = element_converter.CapellaWorkItemSerializer( model, polarion_repo.PolarionDataRepository([ework_item]), {uuid: data_session.ConverterData(layer, type_config, obj)}, False, - prefix, ) work_item = serializer.serialize(uuid)