From 2e24e79a4ca8a63d16596e668e49c6c7aca3f3b4 Mon Sep 17 00:00:00 2001 From: Michael Jerger Date: Mon, 14 Aug 2023 20:39:59 +0200 Subject: [PATCH] introduce artifact class --- doc/architecture/Domain.md | 5 ++- .../application/release_mixin_services.py | 33 ++++++-------- src/main/python/ddadevops/domain/__init__.py | 1 + src/main/python/ddadevops/domain/artifact.py | 43 +++++++++++++++++++ src/main/python/ddadevops/domain/release.py | 7 ++- src/main/python/ddadevops/domain/version.py | 12 +++--- .../infrastructure/infrastructure.py | 15 ++++--- src/test/python/domain/helper.py | 11 +++-- src/test/python/domain/test_artifact.py | 29 +++++++++++++ src/test/python/domain/test_devops_factory.py | 26 +++++++++++ 10 files changed, 143 insertions(+), 39 deletions(-) create mode 100644 src/main/python/ddadevops/domain/artifact.py create mode 100644 src/test/python/domain/test_artifact.py diff --git a/doc/architecture/Domain.md b/doc/architecture/Domain.md index fde909f..3ba7c0b 100644 --- a/doc/architecture/Domain.md +++ b/doc/architecture/Domain.md @@ -94,8 +94,9 @@ classDiagram release_artifact_token } class Artifact { - release_artifact_path - release_artifact_type + path_str + path() + type() } class Credentials { <> diff --git a/src/main/python/ddadevops/application/release_mixin_services.py b/src/main/python/ddadevops/application/release_mixin_services.py index dd9d0d5..0c40e98 100644 --- a/src/main/python/ddadevops/application/release_mixin_services.py +++ b/src/main/python/ddadevops/application/release_mixin_services.py @@ -2,7 +2,7 @@ import json from typing import List from pathlib import Path from ..infrastructure import GitApi, ArtifactDeploymentApi, BuildFileRepository -from ..domain import Version, Release, ReleaseType +from ..domain import Version, Release, ReleaseType, Artifact class ReleaseService: @@ -70,29 +70,20 @@ class ReleaseService: ) ) - artifacts_to_attach = [] - for artifact_path in release.release_artifacts: - self.artifact_deployment_api.calculate_checksums(artifact_path) - # TODO: make api more explizit to have the path calculation & decision which shas to take clear - artifacts_to_attach += [{ - "path": artifact_path, - # TODO: it will not always be a jar file -> move type to release input-side. - "type": "application/x-java-archive", - }, - { - "path": f"{artifact_path}.sha256", - "type": "text/plain", - }, - { - "path": f"{artifact_path}.sha512", - "type": "text/plain", - }] + artifacts_sums = [] + for artifact in release.release_artifacts: + sha256 = self.artifact_deployment_api.calculate_sha256(artifact.path()) + sha512 = self.artifact_deployment_api.calculate_sha512(artifact.path()) + artifacts_sums += [Artifact(sha256), Artifact(sha512)] - for artifact in artifacts_to_attach: + artifacts = release.release_artifacts + artifacts_sums + print(artifacts) + for artifact in artifacts: + print(str) self.artifact_deployment_api.add_asset_to_release( release.forgejo_release_asset_api_endpoint(release_id), - artifact["path"], - artifact["type"], + artifact.path(), + artifact.type(), release.release_artifact_token, ) diff --git a/src/main/python/ddadevops/domain/__init__.py b/src/main/python/ddadevops/domain/__init__.py index 234c48b..6bff258 100644 --- a/src/main/python/ddadevops/domain/__init__.py +++ b/src/main/python/ddadevops/domain/__init__.py @@ -17,6 +17,7 @@ from .provider_hetzner import Hetzner from .provider_aws import Aws from .provs_k3s import K3s from .release import Release +from .artifact import Artifact from .credentials import Credentials, CredentialMapping, GopassType from .version import Version from .build_file import BuildFileType, BuildFile diff --git a/src/main/python/ddadevops/domain/artifact.py b/src/main/python/ddadevops/domain/artifact.py new file mode 100644 index 0000000..fc1d221 --- /dev/null +++ b/src/main/python/ddadevops/domain/artifact.py @@ -0,0 +1,43 @@ +from enum import Enum +from pathlib import Path +from .common import ( + Validateable, +) + +class ArtifactType(Enum): + TEXT = 0 + JAR = 1 + +class Artifact(Validateable): + def __init__(self, path: str): + self.path_str = path + + def path(self) -> Path: + return Path(self.path_str) + + def type(self) -> str: + suffix = self.path().suffix + match suffix: + case ".jar": + return "application/x-java-archive" + case _: + return "text/plain" + + def validate(self): + result = [] + result += self.__validate_is_not_empty__("path_str") + try: + Path(self.path_str) + except Exception as e: + result += [f"path was not a valid: {e}"] + return result + + def __str__(self): + return str(self.path()) + + def __eq__(self, other): + return other and self.__str__() == other.__str__() + + def __hash__(self) -> int: + return self.__str__().__hash__() + diff --git a/src/main/python/ddadevops/domain/release.py b/src/main/python/ddadevops/domain/release.py index f3516cd..e08ae6e 100644 --- a/src/main/python/ddadevops/domain/release.py +++ b/src/main/python/ddadevops/domain/release.py @@ -7,6 +7,9 @@ from .common import ( from .version import ( Version, ) +from .artifact import ( + Artifact, +) class Release(Validateable): @@ -17,7 +20,6 @@ class Release(Validateable): self.release_primary_build_file = inp.get( "release_primary_build_file", "./project.clj" ) - self.release_artifacts = inp.get("release_artifacts", []) self.release_secondary_build_files = inp.get( "release_secondary_build_files", [] ) @@ -26,6 +28,9 @@ class Release(Validateable): self.release_organisation = inp.get("release_organisation") self.release_repository_name = inp.get("release_repository_name") self.release_artifact_token = inp.get("release_artifact_token") + self.release_artifacts = [] + for a in inp.get("release_artifacts", []): + self.release_artifacts.append(Artifact(a)) def update_release_type(self, release_type: ReleaseType): self.release_type = release_type diff --git a/src/main/python/ddadevops/domain/version.py b/src/main/python/ddadevops/domain/version.py index 2f2096a..3c9ac0e 100644 --- a/src/main/python/ddadevops/domain/version.py +++ b/src/main/python/ddadevops/domain/version.py @@ -32,12 +32,6 @@ class Version(Validateable): self.snapshot_suffix = snapshot_suffix self.default_snapshot_suffix = default_snapshot_suffix - def __eq__(self, other): - return other and self.to_string() == other.to_string() - - def __hash__(self) -> int: - return self.to_string().__hash__() - def is_snapshot(self): return self.snapshot_suffix is not None @@ -139,3 +133,9 @@ class Version(Validateable): snapshot_suffix=None, version_str=None, ) + + def __eq__(self, other): + return other and self.to_string() == other.to_string() + + def __hash__(self) -> int: + return self.to_string().__hash__() diff --git a/src/main/python/ddadevops/infrastructure/infrastructure.py b/src/main/python/ddadevops/infrastructure/infrastructure.py index 9708cc6..e94fab9 100644 --- a/src/main/python/ddadevops/infrastructure/infrastructure.py +++ b/src/main/python/ddadevops/infrastructure/infrastructure.py @@ -247,13 +247,16 @@ class ArtifactDeploymentApi: + f'-F "attachment=@{attachment};type={attachment_type}"', ) - def calculate_checksums(self, artifact_path: str): - # self.execution_api.execute(f"find {artifact_path} -type f - # -exec sha256sum {{}}; | sort > {artifact_path} sha256sum.lst") - # relevant für provs + def calculate_sha256(self, path: Path): + sum = f"{path}.sha256" self.execution_api( - f"sha256sum {artifact_path} > {artifact_path}.sha256", + f"sha256sum {path} > {sum}", ) + return sum + + def calculate_sha512(self, path: Path): + sum = f"{path}.sha512" self.execution_api( - f"sha512sum {artifact_path} > {artifact_path}.sha512", + f"sha512sum {path} > {sum}", ) + return sum diff --git a/src/test/python/domain/helper.py b/src/test/python/domain/helper.py index 1740624..7855dc3 100644 --- a/src/test/python/domain/helper.py +++ b/src/test/python/domain/helper.py @@ -168,10 +168,15 @@ class ArtifactDeploymentApiMock: self.create_forgejo_release_count += 1 return self.release - def add_asset_to_release(self, api_endpoint: str, attachment: str, attachment_type: str, token: str): + def add_asset_to_release( + self, api_endpoint: str, attachment: str, attachment_type: str, token: str + ): self.add_asset_to_release_api_endpoint = api_endpoint self.add_asset_to_release_count += 1 pass - def calculate_checksums(self, build_path: str): - pass + def calculate_sha256(self, path: Path): + return f"{path}.sha256" + + def calculate_sha512(self, path: Path): + return f"{path}.sha512" diff --git a/src/test/python/domain/test_artifact.py b/src/test/python/domain/test_artifact.py new file mode 100644 index 0000000..e454c5c --- /dev/null +++ b/src/test/python/domain/test_artifact.py @@ -0,0 +1,29 @@ +import pytest +from pybuilder.core import Project +from pathlib import Path +from src.main.python.ddadevops.domain import ( + Validateable, + DnsRecord, + Devops, + BuildType, + MixinType, + Artifact, + Image, +) +from .helper import build_devops, devops_config + + +def test_sould_validate_release(): + sut = Artifact("x") + assert sut.is_valid() + + sut = Artifact(None) + assert not sut.is_valid() + +def test_should_calculate_type(): + sut = Artifact("x.jar") + assert "application/x-java-archive" == sut.type() + + sut = Artifact("x.jar.sha256") + assert "text/plain" == sut.type() + diff --git a/src/test/python/domain/test_devops_factory.py b/src/test/python/domain/test_devops_factory.py index b9f4008..26cc319 100644 --- a/src/test/python/domain/test_devops_factory.py +++ b/src/test/python/domain/test_devops_factory.py @@ -4,6 +4,7 @@ from src.main.python.ddadevops.domain import ( Version, BuildType, MixinType, + Artifact, ) @@ -50,6 +51,7 @@ def test_devops_creation(): assert sut is not None assert sut.specialized_builds[BuildType.C4K] is not None +def test_release_devops_creation(): sut = DevopsFactory().build_devops( { "stage": "test", @@ -67,6 +69,30 @@ def test_devops_creation(): assert sut is not None assert sut.mixins[MixinType.RELEASE] is not None + sut = DevopsFactory().build_devops( + { + "stage": "test", + "name": "mybuild", + "module": "test_image", + "project_root_path": "../../..", + "build_types": [], + "mixin_types": ["RELEASE"], + "release_main_branch": "main", + "release_current_branch": "my_feature", + "release_config_file": "project.clj", + "release_artifacts": ["x.jar"], + "release_artifact_token": "y", + "release_artifact_server_url": "https://repo.prod.meissa.de", + "release_organisation": "meissa", + "release_repository_name": "provs", + }, + Version.from_str("1.0.0", "SNAPSHOT"), + ) + + release = sut.mixins[MixinType.RELEASE] + assert release is not None + assert Artifact("x.jar") == release.release_artifacts[0] + def test_on_merge_input_should_win(): sut = DevopsFactory()