Skip to content

Commit

Permalink
Merge branch 'main' into fix-grouped-linkfields
Browse files Browse the repository at this point in the history
  • Loading branch information
ewuerger authored Sep 30, 2024
2 parents 5386ec0 + 0a43f94 commit 90df816
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 100 deletions.
77 changes: 59 additions & 18 deletions capella2polarion/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,34 +22,46 @@


@click.group()
@click.option("--debug", is_flag=True, default=False)
@click.option(
"--capella-model",
type=cli_helpers.ModelCLI(),
required=True,
envvar="CAPELLA2POLARION_CAPELLA_MODEL",
)
@click.option(
"--polarion-project-id",
type=str,
required=False,
default=None,
envvar="POLARION_PROJECT_ID",
required=True,
envvar="CAPELLA2POLARION_PROJECT_ID",
)
@click.option(
"--polarion-url",
envvar="POLARION_HOST",
type=str,
required=True,
envvar="POLARION_HOST",
)
@click.option("--polarion-pat", type=str, required=True, envvar="POLARION_PAT")
@click.option(
"--polarion-delete-work-items",
is_flag=True,
default=False,
envvar="CAPELLA2POLARION_DELETE_WORK_ITEMS",
)
@click.option(
"--debug", is_flag=True, envvar="CAPELLA2POLARION_DEBUG", default=False
)
@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.pass_context
def cli(
ctx: click.core.Context,
debug: bool,
capella_model: capellambse.MelodyModel | None,
polarion_project_id: str,
polarion_url: str,
polarion_pat: str,
polarion_delete_work_items: bool,
capella_model: capellambse.MelodyModel,
debug: bool,
) -> None:
"""Synchronise data from Capella to Polarion."""
if capella_model.diagram_cache is None:
if capella_model is not None and capella_model.diagram_cache is None:
logger.warning("It's highly recommended to define a diagram cache!")

capella2polarion_cli = Capella2PolarionCli(
Expand All @@ -76,11 +88,27 @@ def print_cli_state(capella2polarion_cli: Capella2PolarionCli) -> None:
@click.option(
"--synchronize-config",
type=click.File(mode="r", encoding="utf8"),
default=None,
required=True,
envvar="CAPELLA2POLARION_SYNCHRONIZE_CONFIG",
)
@click.option(
"--force-update",
is_flag=True,
envvar="CAPELLA2POLARION_FORCE_UPDATE",
default=False,
)
@click.option(
"--type-prefix",
type=str,
envvar="CAPELLA2POLARION_TYPE_PREFIX",
default="",
)
@click.option(
"--role-prefix",
type=str,
envvar="CAPELLA2POLARION_ROLE_PREFIX",
default="",
)
@click.option("--force-update", is_flag=True, default=False)
@click.option("--type-prefix", type=str, default="")
@click.option("--role-prefix", type=str, default="")
@click.option(
"--grouped-links-custom-fields / --no-grouped-links-custom-fields",
envvar="CAPELLA2POLARION_GROUPED_LINKS_CUSTOM_FIELDS",
Expand All @@ -107,6 +135,7 @@ def synchronize(
)
capella_to_polarion_cli.force_update = force_update

assert capella_to_polarion_cli.capella_model is not None
converter = model_converter.ModelConverter(
capella_to_polarion_cli.capella_model,
capella_to_polarion_cli.polarion_params.project_id,
Expand Down Expand Up @@ -141,10 +170,21 @@ def synchronize(
@click.option(
"--document-rendering-config",
type=click.File(mode="r", encoding="utf8"),
default=None,
required=True,
envvar="CAPELLA2POLARION_DOCUMENT_CONFIG",
)
@click.option(
"--overwrite-layouts",
is_flag=True,
default=False,
envvar="CAPELLA2POLARION_OVERWRITE_LAYOUTS",
)
@click.option(
"--overwrite-numbering",
is_flag=True,
default=False,
envvar="CAPELLA2POLARION_OVERWRITE_NUMBERING",
)
@click.option("--overwrite-layouts", is_flag=True, default=False)
@click.option("--overwrite-numbering", is_flag=True, default=False)
@click.pass_context
def render_documents(
ctx: click.core.Context,
Expand All @@ -168,6 +208,7 @@ def render_documents(
configs.iterate_documents()
)

assert capella_to_polarion_cli.capella_model is not None
renderer = document_renderer.DocumentRenderer(
polarion_worker.polarion_data_repo,
capella_to_polarion_cli.capella_model,
Expand Down
2 changes: 1 addition & 1 deletion capella2polarion/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def __init__(
polarion_url: str,
polarion_pat: str,
polarion_delete_work_items: bool,
capella_model: capellambse.MelodyModel,
capella_model: capellambse.MelodyModel | None,
force_update: bool = False,
) -> None:
self.debug = debug
Expand Down
20 changes: 10 additions & 10 deletions ci-templates/gitlab/render_documents.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@

variables:
CAPELLA2POLARION_DEBUG: "0"
# Remember to set the following environment variables:
# POLARION_HOST
# POLARION_PAT
# CAPELLA2POLARION_PROJECT_ID
# CAPELLA2POLARION_CAPELLA_MODEL
# CAPELLA2POLARION_DOCUMENT_CONFIG
# Optional flags:
# CAPELLA2POLARION_OVERWRITE_LAYOUTS - Overwrite default Live-Doc layouts
# CAPELLA2POLARION_OVERWRITE_NUMBERING - Overwrite default heading numbering

capella2polarion_render_documents:
needs:
Expand All @@ -12,13 +21,4 @@ capella2polarion_render_documents:

script:
- pip install "capella2polarion${CAPELLA2POLARION_VERSION:+==$CAPELLA2POLARION_VERSION}"
- >
python \
-m capella2polarion \
$([[ $CAPELLA2POLARION_DEBUG -eq 1 ]] && echo '--debug') \
--polarion-project-id=${CAPELLA2POLARION_PROJECT_ID:?} \
--capella-model="${CAPELLA2POLARION_MODEL_JSON:?}" \
render-documents \
$([[ $CAPELLA2POLARION_OVERWRITE_LAYOUTS -eq 1 ]] && echo '--overwrite-layouts') \
$([[ $CAPELLA2POLARION_OVERWRITE_NUMBERING -eq 1 ]] && echo '--overwrite-numbering') \
--document-rendering-config="${CAPELLA2POLARION_DOCUMENT_CONFIG:?}"
- capella2polarion render-documents
24 changes: 12 additions & 12 deletions ci-templates/gitlab/synchronise_elements.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,17 @@
# SPDX-License-Identifier: Apache-2.0

variables:
CAPELLA2POLARION_DEBUG: "0"
CAPELLA2POLARION_DEBUG: "1"
# Remember to set the following environment variables:
# POLARION_HOST
# POLARION_PAT
# CAPELLA2POLARION_PROJECT_ID
# CAPELLA2POLARION_CAPELLA_MODEL
# CAPELLA2POLARION_SYNCHRONIZE_CONFIG
# Optional flags:
# CAPELLA2POLARION_FORCE_UPDATE - Simulate initial run
# CAPELLA2POLARION_TYPE_PREFIX - Prefix for work item types
# CAPELLA2POLARION_ROLE_PREFIX - Prefix for work item link roles

capella2polarion_synchronise_elements:
needs:
Expand All @@ -11,14 +21,4 @@ capella2polarion_synchronise_elements:

script:
- pip install "capella2polarion${CAPELLA2POLARION_VERSION:+==$CAPELLA2POLARION_VERSION}"
- >
python \
-m capella2polarion \
$([[ $CAPELLA2POLARION_DEBUG -eq 1 ]] && echo '--debug') \
--polarion-project-id=${CAPELLA2POLARION_PROJECT_ID:?} \
--capella-model="${CAPELLA2POLARION_MODEL_JSON:?}" \
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 synchronize
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ test = [
"pytest-cov",
]

[project.scripts]
capella2polarion = "capella2polarion.__main__:cli"

[tool.black]
line-length = 79
target-version = ["py312"]
Expand Down
140 changes: 81 additions & 59 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from __future__ import annotations

import json
import typing as t
from unittest import mock

import polarion_rest_api_client as polarion_api
Expand All @@ -22,7 +23,21 @@
)


def test_migrate_model_elements(monkeypatch: pytest.MonkeyPatch):
class CLIMocks(t.NamedTuple):
"""Mocks for CLI functions."""

get_polarion_wi_map: mock.MagicMock
generate_work_items: mock.MagicMock
delete_work_items: mock.MagicMock
patch_work_items: mock.MagicMock
post_work_items: mock.MagicMock
get_document: mock.MagicMock
create_documents: mock.MagicMock
update_documents: mock.MagicMock


@pytest.fixture(scope="function")
def cli_mocks(monkeypatch: pytest.MonkeyPatch) -> CLIMocks:
mock_api_client = mock.MagicMock(spec=polarion_api.PolarionClient)
monkeypatch.setattr(polarion_api, "PolarionClient", mock_api_client)
mock_project_client = mock.MagicMock(spec=polarion_api.ProjectClient)
Expand Down Expand Up @@ -57,49 +72,6 @@ def test_migrate_model_elements(monkeypatch: pytest.MonkeyPatch):
"compare_and_update_work_items",
mock_patch_work_items,
)

command: list[str] = [
"--polarion-project-id",
"{project-id}",
"--polarion-url",
"https://www.czy.de",
"--polarion-pat",
"PrivateAcessToken",
"--polarion-delete-work-items",
"--capella-model",
json.dumps(TEST_MODEL),
"synchronize",
"--synchronize-config",
str(TEST_MODEL_ELEMENTS_CONFIG),
"--grouped-links-custom-fields",
]

result = testing.CliRunner().invoke(main.cli, command, terminal_width=60)

assert result.exit_code == 0
assert mock_get_polarion_wi_map.call_count == 1
assert mock_generate_work_items.call_count == 2
assert mock_generate_work_items.call_args_list[1][1] == {
"generate_links": True,
"generate_attachments": True,
"generate_grouped_links_custom_fields": True,
}
assert mock_delete_work_items.call_count == 1
assert mock_patch_work_items.call_count == 1
assert mock_post_work_items.call_count == 1


def test_render_documents(monkeypatch: pytest.MonkeyPatch):
mock_api_client = mock.MagicMock(spec=polarion_api.PolarionClient)
monkeypatch.setattr(polarion_api, "PolarionClient", mock_api_client)
mock_project_client = mock.MagicMock(spec=polarion_api.ProjectClient)
monkeypatch.setattr(polarion_api, "ProjectClient", mock_project_client)
mock_get_polarion_wi_map = mock.MagicMock()
monkeypatch.setattr(
polarion_worker.CapellaPolarionWorker,
"load_polarion_work_item_map",
mock_get_polarion_wi_map,
)
mock_get_document = mock.MagicMock()
mock_get_document.side_effect = lambda folder, name, project_id: (
polarion_api.Document(
Expand Down Expand Up @@ -131,12 +103,56 @@ def test_render_documents(monkeypatch: pytest.MonkeyPatch):
"update_documents",
mock_update_documents,
)
return CLIMocks(
get_polarion_wi_map=mock_get_polarion_wi_map,
generate_work_items=mock_generate_work_items,
delete_work_items=mock_delete_work_items,
patch_work_items=mock_post_work_items,
post_work_items=mock_post_work_items,
get_document=mock_get_document,
create_documents=mock_create_documents,
update_documents=mock_update_documents,
)


# pylint: disable=redefined-outer-name
def test_migrate_model_elements(cli_mocks: CLIMocks):
command: list[str] = [
"--polarion-project-id",
"{project-id}",
"--polarion-url",
"https://www.capella2polarion.invalid",
"--polarion-pat",
"PrivateAcessToken",
"--polarion-delete-work-items",
"--capella-model",
json.dumps(TEST_MODEL),
"synchronize",
"--synchronize-config",
str(TEST_MODEL_ELEMENTS_CONFIG),
"--grouped-links-custom-fields",
]

result = testing.CliRunner().invoke(main.cli, command, terminal_width=60)

assert result.exit_code == 0
assert cli_mocks.get_polarion_wi_map.call_count == 1
assert cli_mocks.generate_work_items.call_count == 2
assert cli_mocks.generate_work_items.call_args_list[1][1] == {
"generate_links": True,
"generate_attachments": True,
}
assert cli_mocks.delete_work_items.call_count == 1
assert cli_mocks.patch_work_items.call_count == 1
assert cli_mocks.post_work_items.call_count == 1


def test_render_documents(cli_mocks: CLIMocks):
command: list[str] = [
"--polarion-project-id",
"{project-id}",
"--polarion-url",
"https://www.czy.de",
"https://www.capella2polarion.invalid",
"--polarion-pat",
"PrivateAcessToken",
"--polarion-delete-work-items",
Expand All @@ -150,9 +166,11 @@ def test_render_documents(monkeypatch: pytest.MonkeyPatch):
result = testing.CliRunner().invoke(main.cli, command, terminal_width=60)

assert result.exit_code == 0
assert mock_get_polarion_wi_map.call_count == 1
assert mock_get_document.call_count == 8
assert [call.args[2] for call in mock_get_document.call_args_list] == [
assert cli_mocks.get_polarion_wi_map.call_count == 1
assert cli_mocks.get_document.call_count == 8
assert [
call.args[2] for call in cli_mocks.get_document.call_args_list
] == [
None,
None,
None,
Expand All @@ -163,14 +181,18 @@ def test_render_documents(monkeypatch: pytest.MonkeyPatch):
"TestProject",
]

assert mock_create_documents.call_count == 2
assert len(mock_create_documents.call_args_list[0].args[0]) == 1
assert len(mock_create_documents.call_args_list[1].args[0]) == 1
assert mock_create_documents.call_args_list[0].args[1] is None
assert mock_create_documents.call_args_list[1].args[1] == "TestProject"

assert mock_update_documents.call_count == 2
assert len(mock_update_documents.call_args_list[0].args[0]) == 1
assert len(mock_update_documents.call_args_list[1].args[0]) == 0
assert mock_update_documents.call_args_list[0].args[1] is None
assert mock_update_documents.call_args_list[1].args[1] == "TestProject"
assert cli_mocks.create_documents.call_count == 2
assert len(cli_mocks.create_documents.call_args_list[0].args[0]) == 1
assert len(cli_mocks.create_documents.call_args_list[1].args[0]) == 1
assert cli_mocks.create_documents.call_args_list[0].args[1] is None
assert (
cli_mocks.create_documents.call_args_list[1].args[1] == "TestProject"
)

assert cli_mocks.update_documents.call_count == 2
assert len(cli_mocks.update_documents.call_args_list[0].args[0]) == 1
assert len(cli_mocks.update_documents.call_args_list[1].args[0]) == 0
assert cli_mocks.update_documents.call_args_list[0].args[1] is None
assert (
cli_mocks.update_documents.call_args_list[1].args[1] == "TestProject"
)

0 comments on commit 90df816

Please sign in to comment.