From e76a6bc03f258a3b2c184bb0f1f9168b18d958e4 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Tue, 4 Jun 2024 20:25:34 +0200 Subject: [PATCH 01/15] upgraded annotations of CLI --- .../src/service_integration/cli.py | 43 +++++++++++-------- .../service_integration/commands/compose.py | 31 +++++++------ .../service_integration/commands/config.py | 36 ++++++++++------ .../service_integration/commands/metadata.py | 35 ++++++++------- .../commands/run_creator.py | 25 ++++++----- .../src/service_integration/commands/test.py | 7 +-- 6 files changed, 105 insertions(+), 72 deletions(-) diff --git a/packages/service-integration/src/service_integration/cli.py b/packages/service-integration/src/service_integration/cli.py index a257be65c14..fe08a2085c8 100644 --- a/packages/service-integration/src/service_integration/cli.py +++ b/packages/service-integration/src/service_integration/cli.py @@ -1,5 +1,6 @@ # Allows entrypoint via python -m as well +from typing import Annotated import rich import typer @@ -11,8 +12,8 @@ app = typer.Typer() -def _version_callback(value: bool): - if value: +def _version_callback(enabled): + if enabled: rich.print(__version__) raise typer.Exit @@ -20,22 +21,28 @@ def _version_callback(value: bool): @app.callback() def main( ctx: typer.Context, - version: bool = typer.Option( - False, - "--version", - callback=_version_callback, - is_eager=True, - ), - registry_name: str = typer.Option( - None, - "--REGISTRY_NAME", - help="image registry name. Full url or prefix used as prefix in an image name", - ), - compose_version: str = typer.Option( - None, - "--COMPOSE_VERSION", - help="version used for docker compose specification", - ), + registry_name: Annotated[ + str, + typer.Option( + "--REGISTRY_NAME", + help="image registry name. Full url or prefix used as prefix in an image name", + ), + ], + compose_version: Annotated[ + str, + typer.Option( + "--COMPOSE_VERSION", + help="version used for docker compose specification", + ), + ] = None, + version: Annotated[ # noqa: FBT002 + bool, + typer.Option( + "--version", + callback=_version_callback, + is_eager=True, + ), + ] = False, ): """o2s2parc service integration library""" assert isinstance(version, bool | None) # nosec diff --git a/packages/service-integration/src/service_integration/commands/compose.py b/packages/service-integration/src/service_integration/commands/compose.py index 3904828cad5..15a4bc07db9 100644 --- a/packages/service-integration/src/service_integration/commands/compose.py +++ b/packages/service-integration/src/service_integration/commands/compose.py @@ -1,6 +1,7 @@ import subprocess from datetime import datetime from pathlib import Path +from typing import Annotated import rich import typer @@ -132,19 +133,23 @@ def create_docker_compose_image_spec( def main( ctx: typer.Context, - config_path: Path = typer.Option( - OSPARC_CONFIG_DIRNAME, - "-m", - "--metadata", - help="osparc config file or folder. " - "If the latter, it will scan for configs using the glob pattern 'config_path/**/metadata.yml' ", - ), - to_spec_file: Path = typer.Option( - Path("docker-compose.yml"), - "-f", - "--to-spec-file", - help="Output docker-compose image spec", - ), + config_path: Annotated[ + Path, + typer.Option( + "-m", + "--metadata", + help="osparc config file or folder. " + "If the latter, it will scan for configs using the glob pattern 'config_path/**/metadata.yml' ", + ), + ] = Path(OSPARC_CONFIG_DIRNAME), + to_spec_file: Annotated[ + Path, + typer.Option( + "-f", + "--to-spec-file", + help="Output docker-compose image spec", + ), + ] = Path("docker-compose.yml"), ): """create docker image/runtime compose-specs from an osparc config""" diff --git a/packages/service-integration/src/service_integration/commands/config.py b/packages/service-integration/src/service_integration/commands/config.py index e1e5b8ef5b1..3feb3c7a102 100644 --- a/packages/service-integration/src/service_integration/commands/config.py +++ b/packages/service-integration/src/service_integration/commands/config.py @@ -1,6 +1,6 @@ import json from pathlib import Path -from typing import Final +from typing import Annotated, Final import rich import typer @@ -17,7 +17,11 @@ ) -def create_osparc_specs( +class InvalidLabelsError(ValueError): + template_msg = "Invalid build labels {build_labels}" + + +def create_config_from_compose_spec( compose_spec_path: Path, docker_compose_overwrite_path: Path = Path("docker-compose.overwrite.yml"), metadata_path: Path = Path("metadata.yml"), @@ -62,8 +66,7 @@ def _save(service_name: str, filename: Path, model: BaseModel): assert isinstance(labels__root__, dict) # nosec labels = labels__root__ else: - msg = f"Invalid build labels {build_labels}" - raise ValueError(msg) + raise InvalidLabelsError(build_labels=build_labels) meta_cfg = MetadataConfig.from_labels_annotations(labels) _save(service_name, metadata_path, meta_cfg) @@ -82,7 +85,12 @@ def _save(service_name: str, filename: Path, model: BaseModel): runtime_cfg = RuntimeConfig.from_labels_annotations(labels) _save(service_name, service_specs_path, runtime_cfg) - except (AttributeError, ValidationError, TypeError, ValueError) as err: + except ( # noqa: PERF203 + AttributeError, + ValidationError, + TypeError, + ValueError, + ) as err: rich.print( f"WARNING: failure producing specs for {service_name}: {err}" ) @@ -91,14 +99,16 @@ def _save(service_name: str, filename: Path, model: BaseModel): def main( - from_spec_file: Path = typer.Option( - Path("docker-compose.yml"), - "-f", - "--from-spec-file", - help="docker-compose used to deduce osparc config", - ), + from_spec_file: Annotated[ + Path, + typer.Option( + "-f", + "--from-spec-file", + help="docker-compose used to deduce osparc config", + ), + ] = Path("docker-compose.yml"), ): - """Creates osparc config from complete docker compose-spec""" + """Creates osparc configuration folder from a complete docker compose-spec""" # TODO: sync defaults among CLI commands config_dir = from_spec_file.parent / OSPARC_CONFIG_DIRNAME project_cfg_path = config_dir / "docker-compose.overwrite.yml" @@ -109,7 +119,7 @@ def main( runtime_cfg_path.parent.mkdir(parents=True, exist_ok=True) rich.print(f"Creating {config_dir} from {from_spec_file} ...") - create_osparc_specs( + create_config_from_compose_spec( from_spec_file, project_cfg_path, meta_cfg_path, runtime_cfg_path ) diff --git a/packages/service-integration/src/service_integration/commands/metadata.py b/packages/service-integration/src/service_integration/commands/metadata.py index eb6e153b7f5..1156f009ade 100644 --- a/packages/service-integration/src/service_integration/commands/metadata.py +++ b/packages/service-integration/src/service_integration/commands/metadata.py @@ -1,6 +1,7 @@ from collections import OrderedDict from enum import Enum from pathlib import Path +from typing import Annotated import rich import typer @@ -24,14 +25,16 @@ class UpgradeTags(str, Enum): def bump_version( - target_version: TargetVersionChoices = typer.Argument( - TargetVersionChoices.SEMANTIC_VERSION - ), - upgrade: UpgradeTags = typer.Option(..., case_sensitive=False), - metadata_file: Path = typer.Option( - "metadata/metadata.yml", - help="The metadata yaml file", - ), + upgrade: Annotated[UpgradeTags, typer.Option(case_sensitive=False)], + metadata_file: Annotated[ + Path, + typer.Option( + help="The metadata yaml file", + ), + ] = Path("metadata/metadata.yml"), + target_version: Annotated[ + TargetVersionChoices, typer.Argument() + ] = TargetVersionChoices.SEMANTIC_VERSION, ): """Bumps target version in metadata (legacy)""" # load @@ -54,13 +57,15 @@ def bump_version( def get_version( - target_version: TargetVersionChoices = typer.Argument( - TargetVersionChoices.SEMANTIC_VERSION - ), - metadata_file: Path = typer.Option( - f"{OSPARC_CONFIG_DIRNAME}/metadata.yml", - help="The metadata yaml file", - ), + target_version: Annotated[ + TargetVersionChoices, typer.Argument() + ] = TargetVersionChoices.SEMANTIC_VERSION, + metadata_file: Annotated[ + Path, + typer.Option( + help="The metadata yaml file", + ), + ] = Path(f"{OSPARC_CONFIG_DIRNAME}/metadata.yml"), ): """Prints to output requested version (legacy)""" diff --git a/packages/service-integration/src/service_integration/commands/run_creator.py b/packages/service-integration/src/service_integration/commands/run_creator.py index 3b08948eeec..cfd49f107dd 100644 --- a/packages/service-integration/src/service_integration/commands/run_creator.py +++ b/packages/service-integration/src/service_integration/commands/run_creator.py @@ -1,5 +1,6 @@ import stat from pathlib import Path +from typing import Annotated import typer import yaml @@ -17,16 +18,20 @@ def get_input_config(metadata_file: Path) -> dict: def main( - metadata_file: Path = typer.Option( - f"{OSPARC_CONFIG_DIRNAME}/metadata.yml", - "--metadata", - help="The metadata yaml of the node", - ), - run_script_file_path: Path = typer.Option( - ..., - "--runscript", - help="Path to the run script ", - ), + run_script_file_path: Annotated[ + Path, + typer.Option( + "--runscript", + help="Path to the run script ", + ), + ], + metadata_file: Annotated[ + Path, + typer.Option( + "--metadata", + help="The metadata yaml of the node", + ), + ] = Path(f"{OSPARC_CONFIG_DIRNAME}/metadata.yml"), ): """Creates a sh script that uses jq tool to retrieve variables to use in sh from a json file for use in an osparc service (legacy). diff --git a/packages/service-integration/src/service_integration/commands/test.py b/packages/service-integration/src/service_integration/commands/test.py index 3bf25551dc2..17a8a921be2 100644 --- a/packages/service-integration/src/service_integration/commands/test.py +++ b/packages/service-integration/src/service_integration/commands/test.py @@ -1,4 +1,5 @@ from pathlib import Path +from typing import Annotated import rich import typer @@ -7,9 +8,9 @@ def main( - service_dir: Path = typer.Argument( - ..., help="Root directory of the service under test" - ), + service_dir: Annotated[ + Path, typer.Argument(help="Root directory of the service under test") + ], ): """Runs tests against service directory""" From 5311bbcfc68eaed376778b4fc3c7dbade7885246 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Tue, 4 Jun 2024 21:26:22 +0200 Subject: [PATCH 02/15] cleanup --- .../service-integration/src/service_integration/cli.py | 8 +++++--- .../src/service_integration/commands/metadata.py | 10 +++++----- .../src/service_integration/osparc_config.py | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/service-integration/src/service_integration/cli.py b/packages/service-integration/src/service_integration/cli.py index fe08a2085c8..9ae54b6b900 100644 --- a/packages/service-integration/src/service_integration/cli.py +++ b/packages/service-integration/src/service_integration/cli.py @@ -12,8 +12,8 @@ app = typer.Typer() -def _version_callback(enabled): - if enabled: +def _version_callback(value: bool): # noqa: FBT002 + if value: rich.print(__version__) raise typer.Exit @@ -27,7 +27,7 @@ def main( "--REGISTRY_NAME", help="image registry name. Full url or prefix used as prefix in an image name", ), - ], + ] = None, compose_version: Annotated[ str, typer.Option( @@ -62,6 +62,8 @@ def main( app.command("compose")(compose.main) app.command("config")(config.main) app.command("test")(test.main) + + # legacy app.command("bump-version")(metadata.bump_version) app.command("get-version")(metadata.get_version) diff --git a/packages/service-integration/src/service_integration/commands/metadata.py b/packages/service-integration/src/service_integration/commands/metadata.py index 1156f009ade..f9688664146 100644 --- a/packages/service-integration/src/service_integration/commands/metadata.py +++ b/packages/service-integration/src/service_integration/commands/metadata.py @@ -1,3 +1,4 @@ +import json from collections import OrderedDict from enum import Enum from pathlib import Path @@ -5,10 +6,8 @@ import rich import typer -import yaml -from models_library.services import ServiceDockerData -from ..osparc_config import OSPARC_CONFIG_DIRNAME +from ..osparc_config import OSPARC_CONFIG_DIRNAME, MetadataConfig from ..versioning import bump_version_string from ..yaml_utils import ordered_safe_dump, ordered_safe_load @@ -41,7 +40,7 @@ def bump_version( raw_data: OrderedDict = ordered_safe_load(metadata_file.read_text()) # parse and validate - metadata = ServiceDockerData(**raw_data) + metadata = MetadataConfig(**raw_data) # get + bump + set attrname = target_version.replace("-", "_") @@ -70,7 +69,7 @@ def get_version( """Prints to output requested version (legacy)""" # parse and validate - metadata = ServiceDockerData(**yaml.safe_load(metadata_file.read_text())) + metadata = MetadataConfig.from_yaml(metadata_file) attrname = target_version.replace("-", "_") current_version: str = getattr(metadata, attrname) @@ -79,3 +78,4 @@ def get_version( # VERSION: $(METADATA) # @simcore-service-integrator get-version --metadata-file $< > $@ rich.print(current_version, end="") + diff --git a/packages/service-integration/src/service_integration/osparc_config.py b/packages/service-integration/src/service_integration/osparc_config.py index 17c5f1d181f..70cb46a570f 100644 --- a/packages/service-integration/src/service_integration/osparc_config.py +++ b/packages/service-integration/src/service_integration/osparc_config.py @@ -94,7 +94,7 @@ class MetadataConfig(ServiceDockerData): @validator("contact") @classmethod - def check_contact_in_authors(cls, v, values): + def _check_contact_in_authors(cls, v, values): """catalog service relies on contact and author to define access rights""" authors_emails = {author.email for author in values["authors"]} if v not in authors_emails: From e3d642099b01e3d0aa0f157e5cc5125b2501bed1 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Wed, 5 Jun 2024 11:27:05 +0200 Subject: [PATCH 03/15] rearranges CLI --- .../src/service_integration/cli.py | 17 ++++++++++---- .../service_integration/commands/compose.py | 6 ++++- .../service_integration/commands/config.py | 23 +++++++++++++++---- .../service_integration/commands/metadata.py | 2 -- .../src/service_integration/commands/test.py | 5 +++- 5 files changed, 40 insertions(+), 13 deletions(-) diff --git a/packages/service-integration/src/service_integration/cli.py b/packages/service-integration/src/service_integration/cli.py index 9ae54b6b900..9d47c630b86 100644 --- a/packages/service-integration/src/service_integration/cli.py +++ b/packages/service-integration/src/service_integration/cli.py @@ -6,7 +6,8 @@ import typer from ._meta import __version__ -from .commands import compose, config, metadata, run_creator, test +from .commands import compose, metadata, run_creator, test +from .commands.config import config_app from .settings import AppSettings app = typer.Typer() @@ -58,13 +59,19 @@ def main( ctx.settings = AppSettings.parse_obj(overrides) -# new -app.command("compose")(compose.main) -app.command("config")(config.main) -app.command("test")(test.main) +app.command("compose")(compose.create_compose) +app.add_typer(config_app, name="config") +app.command("test")(test.run_tests) # legacy + app.command("bump-version")(metadata.bump_version) app.command("get-version")(metadata.get_version) app.command("run-creator")(run_creator.main) + +# Display help message for compose as an alias +@app.callback(invoke_without_command=True) +def callback(ctx: typer.Context): + if ctx.invoked_subcommand is None: + typer.echo("Use --help for more information on specific commands.") diff --git a/packages/service-integration/src/service_integration/commands/compose.py b/packages/service-integration/src/service_integration/commands/compose.py index 15a4bc07db9..bb2939da133 100644 --- a/packages/service-integration/src/service_integration/commands/compose.py +++ b/packages/service-integration/src/service_integration/commands/compose.py @@ -131,7 +131,11 @@ def create_docker_compose_image_spec( ) -def main( +compose_spec_app = typer.Typer() + + +@compose_spec_app.command(name="create") +def create_compose( ctx: typer.Context, config_path: Annotated[ Path, diff --git a/packages/service-integration/src/service_integration/commands/config.py b/packages/service-integration/src/service_integration/commands/config.py index 3feb3c7a102..19dd208a025 100644 --- a/packages/service-integration/src/service_integration/commands/config.py +++ b/packages/service-integration/src/service_integration/commands/config.py @@ -98,7 +98,11 @@ def _save(service_name: str, filename: Path, model: BaseModel): rich.print("osparc config files created") -def main( +config_app = typer.Typer() + + +@config_app.command(name="create") +def create_config( from_spec_file: Annotated[ Path, typer.Option( @@ -124,6 +128,17 @@ def main( ) -if __name__ == "__main__": - # pylint: disable=no-value-for-parameter - main() +@config_app.command(name="init") +def init_config( + template: Annotated[ + str, typer.Option(help="github repo or path to the template") + ] = "gh:pcrespov/cookiecutter-osparc-service", +): + """runs cookie-cutter""" + from cookiecutter.main import cookiecutter + + # The context or checkout value + checkout = "is1404/new-version_display" + + # Execute the cookiecutter command + cookiecutter(template, checkout=checkout) diff --git a/packages/service-integration/src/service_integration/commands/metadata.py b/packages/service-integration/src/service_integration/commands/metadata.py index f9688664146..a06504b3b99 100644 --- a/packages/service-integration/src/service_integration/commands/metadata.py +++ b/packages/service-integration/src/service_integration/commands/metadata.py @@ -1,4 +1,3 @@ -import json from collections import OrderedDict from enum import Enum from pathlib import Path @@ -78,4 +77,3 @@ def get_version( # VERSION: $(METADATA) # @simcore-service-integrator get-version --metadata-file $< > $@ rich.print(current_version, end="") - diff --git a/packages/service-integration/src/service_integration/commands/test.py b/packages/service-integration/src/service_integration/commands/test.py index 17a8a921be2..cb999b32307 100644 --- a/packages/service-integration/src/service_integration/commands/test.py +++ b/packages/service-integration/src/service_integration/commands/test.py @@ -6,8 +6,11 @@ from ..service import pytest_runner +test_app = typer.Typer() -def main( + +@test_app.command("run") +def run_tests( service_dir: Annotated[ Path, typer.Argument(help="Root directory of the service under test") ], From 44e176036d99d25897239953f88a9c8df37d7644 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Wed, 5 Jun 2024 11:28:11 +0200 Subject: [PATCH 04/15] adds cookiecutter dependency --- .../service-integration/requirements/_base.in | 2 ++ .../requirements/_base.txt | 35 +++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/packages/service-integration/requirements/_base.in b/packages/service-integration/requirements/_base.in index a8955a4a9b5..fee8aa856e2 100644 --- a/packages/service-integration/requirements/_base.in +++ b/packages/service-integration/requirements/_base.in @@ -6,7 +6,9 @@ --requirement ../../../packages/models-library/requirements/_base.in click +cookiecutter docker # pytest-plugin +jinja2_time jsonschema # pytest-plugin pytest # pytest-plugin pyyaml diff --git a/packages/service-integration/requirements/_base.txt b/packages/service-integration/requirements/_base.txt index 44411a2736b..391819cffdd 100644 --- a/packages/service-integration/requirements/_base.txt +++ b/packages/service-integration/requirements/_base.txt @@ -1,20 +1,30 @@ arrow==1.3.0 - # via -r requirements/../../../packages/models-library/requirements/_base.in + # via + # -r requirements/../../../packages/models-library/requirements/_base.in + # cookiecutter + # jinja2-time attrs==23.2.0 # via # jsonschema # referencing +binaryornot==0.4.4 + # via cookiecutter certifi==2024.2.2 # via # -c requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt # -c requirements/../../../requirements/constraints.txt # requests +chardet==5.2.0 + # via binaryornot charset-normalizer==3.3.2 # via requests click==8.1.7 # via # -r requirements/_base.in + # cookiecutter # typer +cookiecutter==2.6.0 + # via -r requirements/_base.in dnspython==2.6.1 # via email-validator docker==7.1.0 @@ -29,6 +39,14 @@ idna==3.7 # requests iniconfig==2.0.0 # via pytest +jinja2==3.1.4 + # via + # -c requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt + # -c requirements/../../../requirements/constraints.txt + # cookiecutter + # jinja2-time +jinja2-time==0.2.0 + # via -r requirements/_base.in jsonschema==4.22.0 # via # -r requirements/../../../packages/models-library/requirements/_base.in @@ -37,6 +55,8 @@ jsonschema-specifications==2023.12.1 # via jsonschema markdown-it-py==3.0.0 # via rich +markupsafe==2.1.5 + # via jinja2 mdurl==0.1.2 # via markdown-it-py orjson==3.10.3 @@ -59,19 +79,26 @@ pytest==8.2.0 # via -r requirements/_base.in python-dateutil==2.9.0.post0 # via arrow +python-slugify==8.0.4 + # via cookiecutter pyyaml==6.0.1 # via # -c requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt # -c requirements/../../../requirements/constraints.txt # -r requirements/_base.in + # cookiecutter referencing==0.35.1 # via # jsonschema # jsonschema-specifications requests==2.32.2 - # via docker + # via + # cookiecutter + # docker rich==13.7.1 - # via typer + # via + # cookiecutter + # typer rpds-py==0.18.0 # via # jsonschema @@ -80,6 +107,8 @@ shellingham==1.5.4 # via typer six==1.16.0 # via python-dateutil +text-unidecode==1.3 + # via python-slugify tomli==2.0.1 # via pytest typer==0.12.3 From 9d178486259930fa432e3c64b50cc5da12dd2832 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Wed, 5 Jun 2024 11:42:38 +0200 Subject: [PATCH 05/15] minor --- .../src/service_integration/commands/compose.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/service-integration/src/service_integration/commands/compose.py b/packages/service-integration/src/service_integration/commands/compose.py index bb2939da133..b8600c9f482 100644 --- a/packages/service-integration/src/service_integration/commands/compose.py +++ b/packages/service-integration/src/service_integration/commands/compose.py @@ -131,10 +131,6 @@ def create_docker_compose_image_spec( ) -compose_spec_app = typer.Typer() - - -@compose_spec_app.command(name="create") def create_compose( ctx: typer.Context, config_path: Annotated[ From c6fd42f59f7fb33eb3a50d387d3265d34d8a1757 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Wed, 5 Jun 2024 11:45:22 +0200 Subject: [PATCH 06/15] move to cli --- .../src/service_integration/{cli.py => cli/__init__.py} | 8 ++++---- .../src/service_integration/{commands => cli}/compose.py | 0 .../src/service_integration/{commands => cli}/config.py | 0 .../src/service_integration/{commands => cli}/metadata.py | 0 .../service_integration/{commands => cli}/run_creator.py | 0 .../src/service_integration/{commands => cli}/test.py | 0 .../src/service_integration/commands/__init__.py | 0 .../service-integration/tests/test_command_metadata.py | 2 +- 8 files changed, 5 insertions(+), 5 deletions(-) rename packages/service-integration/src/service_integration/{cli.py => cli/__init__.py} (91%) rename packages/service-integration/src/service_integration/{commands => cli}/compose.py (100%) rename packages/service-integration/src/service_integration/{commands => cli}/config.py (100%) rename packages/service-integration/src/service_integration/{commands => cli}/metadata.py (100%) rename packages/service-integration/src/service_integration/{commands => cli}/run_creator.py (100%) rename packages/service-integration/src/service_integration/{commands => cli}/test.py (100%) delete mode 100644 packages/service-integration/src/service_integration/commands/__init__.py diff --git a/packages/service-integration/src/service_integration/cli.py b/packages/service-integration/src/service_integration/cli/__init__.py similarity index 91% rename from packages/service-integration/src/service_integration/cli.py rename to packages/service-integration/src/service_integration/cli/__init__.py index 9d47c630b86..4842b91681b 100644 --- a/packages/service-integration/src/service_integration/cli.py +++ b/packages/service-integration/src/service_integration/cli/__init__.py @@ -5,10 +5,10 @@ import rich import typer -from ._meta import __version__ -from .commands import compose, metadata, run_creator, test -from .commands.config import config_app -from .settings import AppSettings +from .._meta import __version__ +from ..settings import AppSettings +from . import compose, metadata, run_creator, test +from .config import config_app app = typer.Typer() diff --git a/packages/service-integration/src/service_integration/commands/compose.py b/packages/service-integration/src/service_integration/cli/compose.py similarity index 100% rename from packages/service-integration/src/service_integration/commands/compose.py rename to packages/service-integration/src/service_integration/cli/compose.py diff --git a/packages/service-integration/src/service_integration/commands/config.py b/packages/service-integration/src/service_integration/cli/config.py similarity index 100% rename from packages/service-integration/src/service_integration/commands/config.py rename to packages/service-integration/src/service_integration/cli/config.py diff --git a/packages/service-integration/src/service_integration/commands/metadata.py b/packages/service-integration/src/service_integration/cli/metadata.py similarity index 100% rename from packages/service-integration/src/service_integration/commands/metadata.py rename to packages/service-integration/src/service_integration/cli/metadata.py diff --git a/packages/service-integration/src/service_integration/commands/run_creator.py b/packages/service-integration/src/service_integration/cli/run_creator.py similarity index 100% rename from packages/service-integration/src/service_integration/commands/run_creator.py rename to packages/service-integration/src/service_integration/cli/run_creator.py diff --git a/packages/service-integration/src/service_integration/commands/test.py b/packages/service-integration/src/service_integration/cli/test.py similarity index 100% rename from packages/service-integration/src/service_integration/commands/test.py rename to packages/service-integration/src/service_integration/cli/test.py diff --git a/packages/service-integration/src/service_integration/commands/__init__.py b/packages/service-integration/src/service_integration/commands/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/packages/service-integration/tests/test_command_metadata.py b/packages/service-integration/tests/test_command_metadata.py index 24073dcbc42..6ddf074535c 100644 --- a/packages/service-integration/tests/test_command_metadata.py +++ b/packages/service-integration/tests/test_command_metadata.py @@ -8,7 +8,7 @@ import pytest import yaml -from service_integration.commands.metadata import TargetVersionChoices +from service_integration.cli.metadata import TargetVersionChoices @pytest.fixture From 2c2ae9210614c4708b717f3188838d43a3d698de Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Wed, 5 Jun 2024 11:48:57 +0200 Subject: [PATCH 07/15] fixes main --- .../src/service_integration/cli/__init__.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/packages/service-integration/src/service_integration/cli/__init__.py b/packages/service-integration/src/service_integration/cli/__init__.py index 4842b91681b..236edb07e38 100644 --- a/packages/service-integration/src/service_integration/cli/__init__.py +++ b/packages/service-integration/src/service_integration/cli/__init__.py @@ -45,7 +45,7 @@ def main( ), ] = False, ): - """o2s2parc service integration library""" + """o2s2parc service Integration Library (OOIL in short)""" assert isinstance(version, bool | None) # nosec overrides = {} @@ -59,19 +59,14 @@ def main( ctx.settings = AppSettings.parse_obj(overrides) +# +# REGISTER commands and/or sub-apps +# + app.command("compose")(compose.create_compose) app.add_typer(config_app, name="config") app.command("test")(test.run_tests) - - # legacy - app.command("bump-version")(metadata.bump_version) app.command("get-version")(metadata.get_version) app.command("run-creator")(run_creator.main) - -# Display help message for compose as an alias -@app.callback(invoke_without_command=True) -def callback(ctx: typer.Context): - if ctx.invoked_subcommand is None: - typer.echo("Use --help for more information on specific commands.") From 03436fd3a7e857b058afe0235c2f55d4ae64d61a Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Wed, 5 Jun 2024 11:51:10 +0200 Subject: [PATCH 08/15] fix tests --- .../src/service_integration/cli/config.py | 12 ++++++------ .../service-integration/tests/test_command_config.py | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/service-integration/src/service_integration/cli/config.py b/packages/service-integration/src/service_integration/cli/config.py index 19dd208a025..3aa49369f58 100644 --- a/packages/service-integration/src/service_integration/cli/config.py +++ b/packages/service-integration/src/service_integration/cli/config.py @@ -128,17 +128,17 @@ def create_config( ) +_COOKIECUTTER_GITHUB_URL = "gh:itisfoundation/cookiecutter-osparc-service" + + @config_app.command(name="init") def init_config( template: Annotated[ - str, typer.Option(help="github repo or path to the template") - ] = "gh:pcrespov/cookiecutter-osparc-service", + str, typer.Option(help="Github repo or path to the template") + ] = _COOKIECUTTER_GITHUB_URL, + checkout: Annotated[str, typer.Option(help="Branch if different from main")] = None, ): """runs cookie-cutter""" from cookiecutter.main import cookiecutter - # The context or checkout value - checkout = "is1404/new-version_display" - - # Execute the cookiecutter command cookiecutter(template, checkout=checkout) diff --git a/packages/service-integration/tests/test_command_config.py b/packages/service-integration/tests/test_command_config.py index 08967ba63e6..f6243efd59f 100644 --- a/packages/service-integration/tests/test_command_config.py +++ b/packages/service-integration/tests/test_command_config.py @@ -27,6 +27,7 @@ def test_create_new_osparc_config( result = run_program_with_args( "config", + "create", "--from-spec-file", str(tmp_compose_spec), ) From b72617f48c284b8d7749328fa459115feaa2a797 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Wed, 5 Jun 2024 12:40:29 +0200 Subject: [PATCH 09/15] defaults to local --- packages/service-integration/scripts/ooil.bash | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/service-integration/scripts/ooil.bash b/packages/service-integration/scripts/ooil.bash index 7e5eb116d17..b4527683ef1 100755 --- a/packages/service-integration/scripts/ooil.bash +++ b/packages/service-integration/scripts/ooil.bash @@ -6,7 +6,7 @@ set -o nounset set -o pipefail IFS=$'\n\t' -IMAGE_NAME="${DOCKER_REGISTRY:-itisfoundation}/service-integration:${OOIL_IMAGE_TAG:-master-github-latest}" +IMAGE_NAME="${DOCKER_REGISTRY:-local}/service-integration:${OOIL_IMAGE_TAG:-production}" WORKDIR="$(pwd)" # @@ -20,6 +20,7 @@ WORKDIR="$(pwd)" run() { docker run \ --rm \ + --tty \ --volume="/etc/group:/etc/group:ro" \ --volume="/etc/passwd:/etc/passwd:ro" \ --user="$(id --user "$USER")":"$(id --group "$USER")" \ From 77d978d4bb5a71a54deaa27b01873c08bf011c25 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Wed, 5 Jun 2024 12:45:14 +0200 Subject: [PATCH 10/15] _proected --- .../src/service_integration/cli/__init__.py | 16 ++++++++-------- .../cli/{compose.py => _compose.py} | 2 +- .../cli/{config.py => _config.py} | 4 ++-- .../cli/{metadata.py => _metadata.py} | 0 .../cli/{run_creator.py => _run_creator.py} | 0 .../cli/{test.py => _test.py} | 0 .../tests/test_command_metadata.py | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) rename packages/service-integration/src/service_integration/cli/{compose.py => _compose.py} (98%) rename packages/service-integration/src/service_integration/cli/{config.py => _config.py} (98%) rename packages/service-integration/src/service_integration/cli/{metadata.py => _metadata.py} (100%) rename packages/service-integration/src/service_integration/cli/{run_creator.py => _run_creator.py} (100%) rename packages/service-integration/src/service_integration/cli/{test.py => _test.py} (100%) diff --git a/packages/service-integration/src/service_integration/cli/__init__.py b/packages/service-integration/src/service_integration/cli/__init__.py index 236edb07e38..a19d3dc69aa 100644 --- a/packages/service-integration/src/service_integration/cli/__init__.py +++ b/packages/service-integration/src/service_integration/cli/__init__.py @@ -7,8 +7,8 @@ from .._meta import __version__ from ..settings import AppSettings -from . import compose, metadata, run_creator, test -from .config import config_app +from . import _compose, _metadata, _run_creator, _test +from ._config import config_app app = typer.Typer() @@ -63,10 +63,10 @@ def main( # REGISTER commands and/or sub-apps # -app.command("compose")(compose.create_compose) -app.add_typer(config_app, name="config") -app.command("test")(test.run_tests) +app.command("compose")(_compose.create_compose) +app.add_typer(config_app, name="config", help="Manage osparc config files") +app.command("test")(_test.run_tests) # legacy -app.command("bump-version")(metadata.bump_version) -app.command("get-version")(metadata.get_version) -app.command("run-creator")(run_creator.main) +app.command("bump-version")(_metadata.bump_version) +app.command("get-version")(_metadata.get_version) +app.command("run-creator")(_run_creator.main) diff --git a/packages/service-integration/src/service_integration/cli/compose.py b/packages/service-integration/src/service_integration/cli/_compose.py similarity index 98% rename from packages/service-integration/src/service_integration/cli/compose.py rename to packages/service-integration/src/service_integration/cli/_compose.py index b8600c9f482..25f819a7296 100644 --- a/packages/service-integration/src/service_integration/cli/compose.py +++ b/packages/service-integration/src/service_integration/cli/_compose.py @@ -151,7 +151,7 @@ def create_compose( ), ] = Path("docker-compose.yml"), ): - """create docker image/runtime compose-specs from an osparc config""" + """Creates the docker image/runtime compose-spec file from an .osparc config""" # TODO: all these MUST be replaced by osparc_config.ConfigFilesStructure if not config_path.exists(): diff --git a/packages/service-integration/src/service_integration/cli/config.py b/packages/service-integration/src/service_integration/cli/_config.py similarity index 98% rename from packages/service-integration/src/service_integration/cli/config.py rename to packages/service-integration/src/service_integration/cli/_config.py index 3aa49369f58..38b408e967d 100644 --- a/packages/service-integration/src/service_integration/cli/config.py +++ b/packages/service-integration/src/service_integration/cli/_config.py @@ -21,7 +21,7 @@ class InvalidLabelsError(ValueError): template_msg = "Invalid build labels {build_labels}" -def create_config_from_compose_spec( +def _create_config_from_compose_spec( compose_spec_path: Path, docker_compose_overwrite_path: Path = Path("docker-compose.overwrite.yml"), metadata_path: Path = Path("metadata.yml"), @@ -123,7 +123,7 @@ def create_config( runtime_cfg_path.parent.mkdir(parents=True, exist_ok=True) rich.print(f"Creating {config_dir} from {from_spec_file} ...") - create_config_from_compose_spec( + _create_config_from_compose_spec( from_spec_file, project_cfg_path, meta_cfg_path, runtime_cfg_path ) diff --git a/packages/service-integration/src/service_integration/cli/metadata.py b/packages/service-integration/src/service_integration/cli/_metadata.py similarity index 100% rename from packages/service-integration/src/service_integration/cli/metadata.py rename to packages/service-integration/src/service_integration/cli/_metadata.py diff --git a/packages/service-integration/src/service_integration/cli/run_creator.py b/packages/service-integration/src/service_integration/cli/_run_creator.py similarity index 100% rename from packages/service-integration/src/service_integration/cli/run_creator.py rename to packages/service-integration/src/service_integration/cli/_run_creator.py diff --git a/packages/service-integration/src/service_integration/cli/test.py b/packages/service-integration/src/service_integration/cli/_test.py similarity index 100% rename from packages/service-integration/src/service_integration/cli/test.py rename to packages/service-integration/src/service_integration/cli/_test.py diff --git a/packages/service-integration/tests/test_command_metadata.py b/packages/service-integration/tests/test_command_metadata.py index 6ddf074535c..7204fc953c6 100644 --- a/packages/service-integration/tests/test_command_metadata.py +++ b/packages/service-integration/tests/test_command_metadata.py @@ -8,7 +8,7 @@ import pytest import yaml -from service_integration.cli.metadata import TargetVersionChoices +from service_integration.cli._metadata import TargetVersionChoices @pytest.fixture From 90cb193ed02a9a689a726748f255359889c4f408 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Wed, 5 Jun 2024 13:53:03 +0200 Subject: [PATCH 11/15] sonar on _compose_spec --- .../src/service_integration/cli/__init__.py | 4 ++-- .../cli/{_compose.py => _compose_spec.py} | 22 ++++++++----------- .../src/service_integration/errors.py | 4 ++++ 3 files changed, 15 insertions(+), 15 deletions(-) rename packages/service-integration/src/service_integration/cli/{_compose.py => _compose_spec.py} (92%) diff --git a/packages/service-integration/src/service_integration/cli/__init__.py b/packages/service-integration/src/service_integration/cli/__init__.py index a19d3dc69aa..51a185e8c8b 100644 --- a/packages/service-integration/src/service_integration/cli/__init__.py +++ b/packages/service-integration/src/service_integration/cli/__init__.py @@ -7,7 +7,7 @@ from .._meta import __version__ from ..settings import AppSettings -from . import _compose, _metadata, _run_creator, _test +from . import _compose_spec, _metadata, _run_creator, _test from ._config import config_app app = typer.Typer() @@ -63,7 +63,7 @@ def main( # REGISTER commands and/or sub-apps # -app.command("compose")(_compose.create_compose) +app.command("compose")(_compose_spec.create_compose) app.add_typer(config_app, name="config", help="Manage osparc config files") app.command("test")(_test.run_tests) # legacy diff --git a/packages/service-integration/src/service_integration/cli/_compose.py b/packages/service-integration/src/service_integration/cli/_compose_spec.py similarity index 92% rename from packages/service-integration/src/service_integration/cli/_compose.py rename to packages/service-integration/src/service_integration/cli/_compose_spec.py index 25f819a7296..2c23c9fd786 100644 --- a/packages/service-integration/src/service_integration/cli/_compose.py +++ b/packages/service-integration/src/service_integration/cli/_compose_spec.py @@ -1,5 +1,5 @@ +import datetime import subprocess -from datetime import datetime from pathlib import Path from typing import Annotated @@ -10,6 +10,7 @@ from rich.console import Console from ..compose_spec_model import ComposeSpecification +from ..errors import UndefinedOciImageSpec from ..oci_image_spec import LS_LABEL_PREFIX, OCI_LABEL_PREFIX from ..osparc_config import ( OSPARC_CONFIG_DIRNAME, @@ -79,7 +80,6 @@ def create_docker_compose_image_spec( runtime_cfg = None if service_config_path: try: - # TODO: should include default? runtime_cfg = RuntimeConfig.from_yaml(service_config_path) except FileNotFoundError: rich.print("No runtime config found (optional), using default.") @@ -91,13 +91,11 @@ def create_docker_compose_image_spec( (config_basedir / f"{OCI_LABEL_PREFIX}.yml").read_text() ) if not oci_spec: - msg = "Undefined OCI image spec" - raise ValueError(msg) + raise UndefinedOciImageSpec oci_labels = to_labels(oci_spec, prefix_key=OCI_LABEL_PREFIX) extra_labels.update(oci_labels) - except (FileNotFoundError, ValueError): - + except (FileNotFoundError, UndefinedOciImageSpec): try: # if not OCI, try label-schema ls_spec = yaml.safe_load( @@ -110,9 +108,9 @@ def create_docker_compose_image_spec( "No explicit config for OCI/label-schema found (optional), skipping OCI annotations." ) # add required labels - extra_labels[f"{LS_LABEL_PREFIX}.build-date"] = datetime.utcnow().strftime( - "%Y-%m-%dT%H:%M:%SZ" - ) + extra_labels[f"{LS_LABEL_PREFIX}.build-date"] = datetime.datetime.now( + datetime.timezone.utc + ).strftime("%Y-%m-%dT%H:%M:%SZ") extra_labels[f"{LS_LABEL_PREFIX}.schema-version"] = "1.0" extra_labels[f"{LS_LABEL_PREFIX}.vcs-ref"] = _run_git_or_empty_string( @@ -153,7 +151,6 @@ def create_compose( ): """Creates the docker image/runtime compose-spec file from an .osparc config""" - # TODO: all these MUST be replaced by osparc_config.ConfigFilesStructure if not config_path.exists(): msg = "Invalid path to metadata file or folder" raise typer.BadParameter(msg) @@ -173,10 +170,10 @@ def create_compose( config_name = meta_config.parent.name configs_kwargs_map[config_name] = {} - # load meta [required] + # load meta REQUIRED configs_kwargs_map[config_name]["meta_config_path"] = meta_config - # others [optional] + # others OPTIONAL for file_name, arg_name in ( ("docker-compose.overwrite.yml", "docker_compose_overwrite_path"), ("runtime.yml", "service_config_path"), @@ -199,7 +196,6 @@ def create_compose( settings, **configs_kwargs_map[config_name] ).dict(exclude_unset=True) - # FIXME: shaky! why first decides ?? if n == 0: compose_spec_dict = nth_compose_spec else: diff --git a/packages/service-integration/src/service_integration/errors.py b/packages/service-integration/src/service_integration/errors.py index e9a857edc1c..bf648a86736 100644 --- a/packages/service-integration/src/service_integration/errors.py +++ b/packages/service-integration/src/service_integration/errors.py @@ -7,3 +7,7 @@ class ServiceIntegrationError(PydanticErrorMixin, RuntimeError): class ConfigNotFoundError(ServiceIntegrationError): msg_template = "could not find any osparc config under {basedir}" + + +class UndefinedOciImageSpec(ServiceIntegrationError): + ... From d8611d4f7d27aeda4bf2068ed1c80d0666893abc Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Wed, 5 Jun 2024 14:03:42 +0200 Subject: [PATCH 12/15] sonar on _config --- .../service_integration/cli/_compose_spec.py | 12 +++--- .../src/service_integration/cli/_config.py | 42 +++++++++---------- .../src/service_integration/errors.py | 6 ++- .../src/service_integration/osparc_config.py | 3 ++ 4 files changed, 35 insertions(+), 28 deletions(-) diff --git a/packages/service-integration/src/service_integration/cli/_compose_spec.py b/packages/service-integration/src/service_integration/cli/_compose_spec.py index 2c23c9fd786..23cc82ad029 100644 --- a/packages/service-integration/src/service_integration/cli/_compose_spec.py +++ b/packages/service-integration/src/service_integration/cli/_compose_spec.py @@ -10,7 +10,7 @@ from rich.console import Console from ..compose_spec_model import ComposeSpecification -from ..errors import UndefinedOciImageSpec +from ..errors import UndefinedOciImageSpecError from ..oci_image_spec import LS_LABEL_PREFIX, OCI_LABEL_PREFIX from ..osparc_config import ( OSPARC_CONFIG_DIRNAME, @@ -63,10 +63,10 @@ def create_docker_compose_image_spec( config_basedir = meta_config_path.parent - # required + # REQUIRED meta_cfg = MetadataConfig.from_yaml(meta_config_path) - # required + # REQUIRED if docker_compose_overwrite_path: docker_compose_overwrite_cfg = DockerComposeOverwriteConfig.from_yaml( docker_compose_overwrite_path @@ -76,7 +76,7 @@ def create_docker_compose_image_spec( service_name=meta_cfg.service_name() ) - # optional + # OPTIONAL runtime_cfg = None if service_config_path: try: @@ -91,11 +91,11 @@ def create_docker_compose_image_spec( (config_basedir / f"{OCI_LABEL_PREFIX}.yml").read_text() ) if not oci_spec: - raise UndefinedOciImageSpec + raise UndefinedOciImageSpecError oci_labels = to_labels(oci_spec, prefix_key=OCI_LABEL_PREFIX) extra_labels.update(oci_labels) - except (FileNotFoundError, UndefinedOciImageSpec): + except (FileNotFoundError, UndefinedOciImageSpecError): try: # if not OCI, try label-schema ls_spec = yaml.safe_load( diff --git a/packages/service-integration/src/service_integration/cli/_config.py b/packages/service-integration/src/service_integration/cli/_config.py index 38b408e967d..54802fe6996 100644 --- a/packages/service-integration/src/service_integration/cli/_config.py +++ b/packages/service-integration/src/service_integration/cli/_config.py @@ -5,27 +5,37 @@ import rich import typer import yaml -from pydantic import ValidationError -from pydantic.main import BaseModel +from pydantic import BaseModel from ..compose_spec_model import ComposeSpecification +from ..errors import InvalidLabelsError from ..osparc_config import ( + OSPARC_CONFIG_COMPOSE_SPEC_NAME, OSPARC_CONFIG_DIRNAME, + OSPARC_CONFIG_METADATA_NAME, + OSPARC_CONFIG_RUNTIME_NAME, DockerComposeOverwriteConfig, MetadataConfig, RuntimeConfig, ) -class InvalidLabelsError(ValueError): - template_msg = "Invalid build labels {build_labels}" +def _get_labels_or_raise(build_labels) -> dict[str, str]: + if isinstance(build_labels, list): + return dict(item.strip().split("=") for item in build_labels) + if isinstance(build_labels, dict): + return build_labels + if labels__root__ := build_labels.__root__: + assert isinstance(labels__root__, dict) # nosec + return labels__root__ + raise InvalidLabelsError(build_labels=build_labels) def _create_config_from_compose_spec( compose_spec_path: Path, - docker_compose_overwrite_path: Path = Path("docker-compose.overwrite.yml"), - metadata_path: Path = Path("metadata.yml"), - service_specs_path: Path = Path("runtime-spec.yml"), + docker_compose_overwrite_path: Path, + metadata_path: Path, + service_specs_path: Path, ): rich.print(f"Creating osparc config files from {compose_spec_path}") @@ -58,16 +68,8 @@ def _save(service_name: str, filename: Path, model: BaseModel): if build_labels := compose_spec.services[ service_name ].build.labels: # AttributeError if build is str - if isinstance(build_labels, list): - labels = dict(item.strip().split("=") for item in build_labels) - elif isinstance(build_labels, dict): - labels = build_labels - elif labels__root__ := build_labels.__root__: - assert isinstance(labels__root__, dict) # nosec - labels = labels__root__ - else: - raise InvalidLabelsError(build_labels=build_labels) + labels: dict[str, str] = _get_labels_or_raise(build_labels) meta_cfg = MetadataConfig.from_labels_annotations(labels) _save(service_name, metadata_path, meta_cfg) @@ -87,7 +89,6 @@ def _save(service_name: str, filename: Path, model: BaseModel): except ( # noqa: PERF203 AttributeError, - ValidationError, TypeError, ValueError, ) as err: @@ -113,11 +114,10 @@ def create_config( ] = Path("docker-compose.yml"), ): """Creates osparc configuration folder from a complete docker compose-spec""" - # TODO: sync defaults among CLI commands config_dir = from_spec_file.parent / OSPARC_CONFIG_DIRNAME - project_cfg_path = config_dir / "docker-compose.overwrite.yml" - meta_cfg_path = config_dir / "metadata.yml" - runtime_cfg_path = config_dir / "runtime.yml" + project_cfg_path = config_dir / OSPARC_CONFIG_COMPOSE_SPEC_NAME + meta_cfg_path = config_dir / OSPARC_CONFIG_METADATA_NAME + runtime_cfg_path = config_dir / OSPARC_CONFIG_RUNTIME_NAME meta_cfg_path.parent.mkdir(parents=True, exist_ok=True) runtime_cfg_path.parent.mkdir(parents=True, exist_ok=True) diff --git a/packages/service-integration/src/service_integration/errors.py b/packages/service-integration/src/service_integration/errors.py index bf648a86736..8d216b7d918 100644 --- a/packages/service-integration/src/service_integration/errors.py +++ b/packages/service-integration/src/service_integration/errors.py @@ -9,5 +9,9 @@ class ConfigNotFoundError(ServiceIntegrationError): msg_template = "could not find any osparc config under {basedir}" -class UndefinedOciImageSpec(ServiceIntegrationError): +class UndefinedOciImageSpecError(ServiceIntegrationError): ... + + +class InvalidLabelsError(PydanticErrorMixin, ValueError): + template_msg = "Invalid build labels {build_labels}" diff --git a/packages/service-integration/src/service_integration/osparc_config.py b/packages/service-integration/src/service_integration/osparc_config.py index 70cb46a570f..51b2f254f08 100644 --- a/packages/service-integration/src/service_integration/osparc_config.py +++ b/packages/service-integration/src/service_integration/osparc_config.py @@ -49,6 +49,9 @@ _logger = logging.getLogger(__name__) OSPARC_CONFIG_DIRNAME = ".osparc" +OSPARC_CONFIG_COMPOSE_SPEC_NAME = "docker-compose.overwrite.yml" +OSPARC_CONFIG_METADATA_NAME = "metadata.yml" +OSPARC_CONFIG_RUNTIME_NAME = "runtime.yml" SERVICE_KEY_FORMATS = { From 57e71605be1c942e46af971dcfd223ac6f174619 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Wed, 5 Jun 2024 14:07:06 +0200 Subject: [PATCH 13/15] sonar on _config --- .../src/service_integration/cli/__init__.py | 2 +- .../src/service_integration/cli/_run_creator.py | 11 +++-------- .../src/service_integration/osparc_config.py | 10 +++++----- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/packages/service-integration/src/service_integration/cli/__init__.py b/packages/service-integration/src/service_integration/cli/__init__.py index 51a185e8c8b..26b9697633c 100644 --- a/packages/service-integration/src/service_integration/cli/__init__.py +++ b/packages/service-integration/src/service_integration/cli/__init__.py @@ -69,4 +69,4 @@ def main( # legacy app.command("bump-version")(_metadata.bump_version) app.command("get-version")(_metadata.get_version) -app.command("run-creator")(_run_creator.main) +app.command("run-creator")(_run_creator.run_creator) diff --git a/packages/service-integration/src/service_integration/cli/_run_creator.py b/packages/service-integration/src/service_integration/cli/_run_creator.py index cfd49f107dd..8cadef194a4 100644 --- a/packages/service-integration/src/service_integration/cli/_run_creator.py +++ b/packages/service-integration/src/service_integration/cli/_run_creator.py @@ -5,7 +5,7 @@ import typer import yaml -from ..osparc_config import OSPARC_CONFIG_DIRNAME +from ..osparc_config import OSPARC_CONFIG_DIRNAME, OSPARC_CONFIG_METADATA_NAME def get_input_config(metadata_file: Path) -> dict: @@ -17,7 +17,7 @@ def get_input_config(metadata_file: Path) -> dict: return inputs -def main( +def run_creator( run_script_file_path: Annotated[ Path, typer.Option( @@ -31,7 +31,7 @@ def main( "--metadata", help="The metadata yaml of the node", ), - ] = Path(f"{OSPARC_CONFIG_DIRNAME}/metadata.yml"), + ] = Path(f"{OSPARC_CONFIG_DIRNAME}/{OSPARC_CONFIG_METADATA_NAME}"), ): """Creates a sh script that uses jq tool to retrieve variables to use in sh from a json file for use in an osparc service (legacy). @@ -84,8 +84,3 @@ def main( run_script_file_path.write_text(shell_script) st = run_script_file_path.stat() run_script_file_path.chmod(st.st_mode | stat.S_IEXEC) - - -if __name__ == "__main__": - # pylint: disable=no-value-for-parameter - main() diff --git a/packages/service-integration/src/service_integration/osparc_config.py b/packages/service-integration/src/service_integration/osparc_config.py index 51b2f254f08..b3eb998e7dd 100644 --- a/packages/service-integration/src/service_integration/osparc_config.py +++ b/packages/service-integration/src/service_integration/osparc_config.py @@ -14,7 +14,7 @@ import logging from pathlib import Path -from typing import Any, Literal +from typing import Any, Final, Literal from models_library.callbacks_mapping import CallbacksMapping from models_library.service_settings_labels import ( @@ -48,10 +48,10 @@ _logger = logging.getLogger(__name__) -OSPARC_CONFIG_DIRNAME = ".osparc" -OSPARC_CONFIG_COMPOSE_SPEC_NAME = "docker-compose.overwrite.yml" -OSPARC_CONFIG_METADATA_NAME = "metadata.yml" -OSPARC_CONFIG_RUNTIME_NAME = "runtime.yml" +OSPARC_CONFIG_DIRNAME: Final[str] = ".osparc" +OSPARC_CONFIG_COMPOSE_SPEC_NAME: Final[str] = "docker-compose.overwrite.yml" +OSPARC_CONFIG_METADATA_NAME: Final[str] = "metadata.yml" +OSPARC_CONFIG_RUNTIME_NAME: Final[str] = "runtime.yml" SERVICE_KEY_FORMATS = { From a98f3a9592563e41031663558b22e92b12e67370 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Thu, 6 Jun 2024 10:55:33 +0200 Subject: [PATCH 14/15] fixes mypy --- .../service-integration/src/service_integration/cli/_config.py | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/service-integration/src/service_integration/cli/_config.py b/packages/service-integration/src/service_integration/cli/_config.py index 54802fe6996..9932140a48e 100644 --- a/packages/service-integration/src/service_integration/cli/_config.py +++ b/packages/service-integration/src/service_integration/cli/_config.py @@ -63,7 +63,6 @@ def _save(service_name: str, filename: Path, model: BaseModel): for service_name in compose_spec.services: try: - labels: dict[str, str] = {} if build_labels := compose_spec.services[ service_name From b168040e056e5422f44d505ecfaf6f10d82d0e5b Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Thu, 6 Jun 2024 18:12:21 +0200 Subject: [PATCH 15/15] @sanderegg @GitHK reviews: rfc 3339 --- .../src/service_integration/cli/_compose_spec.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/service-integration/src/service_integration/cli/_compose_spec.py b/packages/service-integration/src/service_integration/cli/_compose_spec.py index 23cc82ad029..c2f2477c622 100644 --- a/packages/service-integration/src/service_integration/cli/_compose_spec.py +++ b/packages/service-integration/src/service_integration/cli/_compose_spec.py @@ -1,8 +1,8 @@ -import datetime import subprocess from pathlib import Path from typing import Annotated +import arrow import rich import typer import yaml @@ -108,9 +108,11 @@ def create_docker_compose_image_spec( "No explicit config for OCI/label-schema found (optional), skipping OCI annotations." ) # add required labels - extra_labels[f"{LS_LABEL_PREFIX}.build-date"] = datetime.datetime.now( - datetime.timezone.utc - ).strftime("%Y-%m-%dT%H:%M:%SZ") + + # SEE https://github.com/opencontainers/image-spec/blob/main/annotations.md#pre-defined-annotation-keys + # Format the datetime object as a string following RFC-3339 + rfc3339_format = arrow.now().format("YYYY-MM-DDTHH:mm:ssZ") + extra_labels[f"{LS_LABEL_PREFIX}.build-date"] = rfc3339_format extra_labels[f"{LS_LABEL_PREFIX}.schema-version"] = "1.0" extra_labels[f"{LS_LABEL_PREFIX}.vcs-ref"] = _run_git_or_empty_string(