diff --git a/build.py b/build.py index bb47bcd..404fcbb 100644 --- a/build.py +++ b/build.py @@ -28,7 +28,7 @@ use_plugin("python.distutils") default_task = "publish" name = "ddadevops" -version = "3.1.3" +version = "3.2.0-dev" summary = "tools to support builds combining gopass, terraform, dda-pallet, aws & hetzner-cloud" description = __doc__ authors = [Author("meissa GmbH", "buero@meissa-gmbh.de")] diff --git a/doc/architecture/Domain.md b/doc/architecture/Domain.md index 133940d..8684547 100644 --- a/doc/architecture/Domain.md +++ b/doc/architecture/Domain.md @@ -6,5 +6,10 @@ classDiagram __init__(project, config) do_sth(project) } + + class ProjectRepository { + get_build(project): Build + set_build(project, build) + } ``` \ No newline at end of file diff --git a/src/main/python/ddadevops/__init__.py b/src/main/python/ddadevops/__init__.py index b423561..f1411b8 100644 --- a/src/main/python/ddadevops/__init__.py +++ b/src/main/python/ddadevops/__init__.py @@ -20,6 +20,7 @@ from .devops_build import DevopsBuild, create_devops_build_config, get_devops_bu from .credential import gopass_password_from_path, gopass_field_from_path from .domain import Validateable, Build, DockerBuild, C4kBuild -from .application import BuildService, DockerBuildService, C4kBuildService +from .application import DockerBuildService, C4kBuildService +from .infrastructure import ProjectRepository, ResourceApi, FileApi, DockerApi, ExecutionApi __version__ = "${version}" diff --git a/src/main/python/ddadevops/application.py b/src/main/python/ddadevops/application.py index a2c9632..975a0f4 100644 --- a/src/main/python/ddadevops/application.py +++ b/src/main/python/ddadevops/application.py @@ -2,14 +2,6 @@ from .domain import Build, DockerBuild, C4kBuild from .infrastructure import FileApi, ResourceApi, DockerApi, ExecutionApi -class BuildService: - def __init__(self): - self.file_api = FileApi() - - def initialize_build_dir(self, build: Build): - self.file_api.clean_dir(build.build_path()) - - class DockerBuildService: def __init__(self): self.file_api = FileApi() diff --git a/src/main/python/ddadevops/devops_build.py b/src/main/python/ddadevops/devops_build.py index 5087a90..219b0e2 100644 --- a/src/main/python/ddadevops/devops_build.py +++ b/src/main/python/ddadevops/devops_build.py @@ -1,5 +1,6 @@ +import deprecation from .domain import Build -from .application import BuildService +from .infrastructure import ProjectRepository, FileApi def create_devops_build_config( @@ -12,7 +13,8 @@ def create_devops_build_config( "build_dir_name": build_dir_name, } - +@deprecation.deprecated(deprecated_in="3.2") +# Do not expose build to outside def get_devops_build(project): return project.get_property("devops_build") @@ -33,15 +35,20 @@ def get_tag_from_latest_commit(): class DevopsBuild: def __init__(self, project, config): - self.build = Build(project, config) - self.build_service = BuildService() - project.set_property("devops_build", self) + self.project = project + self.file_api = FileApi() + self.repo = ProjectRepository() + config.update({"name": project.name}) + build = Build(config) + self.repo.set_build(self.project, build) def name(self): - return self.build.name() + build = self.repo.get_build(self.project) + return build.name def build_path(self): - return self.build.build_path() + build = self.repo.get_build(self.project) + return build.build_path() def initialize_build_dir(self): - self.build_service.initialize_build_dir(self.build) + self.file_api.clean_dir(build.build_path()) diff --git a/src/main/python/ddadevops/domain.py b/src/main/python/ddadevops/domain.py index bfb0d44..921eeaf 100644 --- a/src/main/python/ddadevops/domain.py +++ b/src/main/python/ddadevops/domain.py @@ -1,3 +1,4 @@ +import deprecation from typing import List from .python_util import filter_none @@ -18,26 +19,29 @@ class Validateable: class Build(Validateable): - def __init__(self, project, config): + def __init__(self, config): self.stage = config["stage"] + self.name = config["name"] self.project_root_path = config["project_root_path"] self.module = config["module"] self.build_dir_name = config["build_dir_name"] + # Deprecated - no longer use generic stack ... self.stack = {} - self.project = project + @deprecation.deprecated(deprecated_in="3.2") + # use .name instead def name(self): - return self.project.name + return self.name def build_path(self): - path = [self.project_root_path, self.build_dir_name, self.name(), self.module] + path = [self.project_root_path, self.build_dir_name, self.name, self.module] return "/".join(filter_none(path)) # TODO: these functions should be located at TerraformBuild later on. def update_runtime_config(self, fqdn, ipv4, ipv6): - self.__put__('fqdn', fqdn) - self.__put__('ipv4', ipv4) - self.__put__('ipv6', ipv6) + self.__put__("fqdn", fqdn) + self.__put__("ipv4", ipv4) + self.__put__("ipv6", ipv6) def __put__(self, key, value): self.stack[key] = value @@ -78,15 +82,17 @@ class C4kBuild(Validateable): self.c4k_mixin_config = config["C4kMixin"]["config"] self.c4k_mixin_auth = config["C4kMixin"]["auth"] tmp = self.c4k_mixin_config["mon-cfg"] - tmp.update({"cluster-name": self.build.module, "cluster-stage": self.build.stage}) + tmp.update( + {"cluster-name": self.build.module, "cluster-stage": self.build.stage} + ) self.c4k_mixin_config.update({"mon-cfg": tmp}) def update_runtime_config(self, fqdn, ipv4, ipv6): self.build.update_runtime_config(fqdn, ipv4, ipv6) def config(self): - fqdn = self.build.__get__('fqdn') - self.c4k_mixin_config.update({'fqdn': fqdn}) + fqdn = self.build.__get__("fqdn") + self.c4k_mixin_config.update({"fqdn": fqdn}) return self.c4k_mixin_config def command(self): diff --git a/src/main/python/ddadevops/infrastructure.py b/src/main/python/ddadevops/infrastructure.py index ba07c67..aef9d73 100644 --- a/src/main/python/ddadevops/infrastructure.py +++ b/src/main/python/ddadevops/infrastructure.py @@ -3,22 +3,33 @@ from sys import stdout from pkg_resources import resource_string from os import chmod import yaml +from .domain import Build from .python_util import execute -class ResourceApi(): + +class ProjectRepository: + def get_build(self, project) -> Build: + return project.get_property("devops_build") + + def set_build(self, project, build: Build): + project.set_property("devops_build", build) + + +class ResourceApi: def read_resource(self, path: str) -> bytes: return resource_string(__name__, path) -class FileApi(): + +class FileApi: def clean_dir(self, directory: str): - execute('rm -rf ' + directory, shell=True) - execute('mkdir -p ' + directory, shell=True) + execute("rm -rf " + directory, shell=True) + execute("mkdir -p " + directory, shell=True) def cp_force(self, src: str, target_dir: str): - execute('cp -f ' + src + '* ' + target_dir, shell=True) + execute("cp -f " + src + "* " + target_dir, shell=True) def cp_recursive(self, src: str, target_dir: str): - execute('cp -r ' + src + ' ' + target_dir, shell=True) + execute("cp -r " + src + " " + target_dir, shell=True) def write_data_to_file(self, path: Path, data: bytes): with open(path, "w", encoding="utf-8") as output_file: @@ -29,37 +40,56 @@ class FileApi(): yaml.dump(data, output_file) chmod(path, 0o600) -class DockerApi(): + +class DockerApi: def image(self, name: str, path: Path): - execute('docker build -t ' + name + - ' --file ' + path + '/image/Dockerfile ' - + path + '/image', shell=True) + execute( + "docker build -t " + + name + + " --file " + + path + + "/image/Dockerfile " + + path + + "/image", + shell=True, + ) def drun(self, name: str): - execute('docker run -it --entrypoint="" ' + - name + ' /bin/bash', shell=True) + execute('docker run -it --entrypoint="" ' + name + " /bin/bash", shell=True) def dockerhub_login(self, username: str, password: str): - execute('docker login --username ' + username + - ' --password ' + password, shell=True) + execute( + "docker login --username " + username + " --password " + password, + shell=True, + ) def dockerhub_publish(self, name: str, username: str, tag=None): if tag is not None: - execute('docker tag ' + name + ' ' + username + - '/' + name + ':' + tag, shell=True) - execute('docker push ' + username + - '/' + name + ':' + tag, shell=True) - execute('docker tag ' + name + ' ' + username + - '/' + name + ':latest', shell=True) - execute('docker push ' + username + - '/' + name + ':latest', shell=True) + execute( + "docker tag " + name + " " + username + "/" + name + ":" + tag, + shell=True, + ) + execute("docker push " + username + "/" + name + ":" + tag, shell=True) + execute( + "docker tag " + name + " " + username + "/" + name + ":latest", shell=True + ) + execute("docker push " + username + "/" + name + ":latest", shell=True) def test(self, name: str, path: Path): - execute('docker build -t ' + name + '-test ' + - '--file ' + path + '/test/Dockerfile ' - + path + '/test', shell=True) + execute( + "docker build -t " + + name + + "-test " + + "--file " + + path + + "/test/Dockerfile " + + path + + "/test", + shell=True, + ) -class ExecutionApi(): + +class ExecutionApi: def execute(command: str, dry_run=False): output = "" if dry_run: @@ -67,4 +97,4 @@ class ExecutionApi(): else: output = execute(command, True) print(output) - return output \ No newline at end of file + return output diff --git a/src/test/python/test_domain.py b/src/test/python/test_domain.py index c2baf3b..32f45be 100644 --- a/src/test/python/test_domain.py +++ b/src/test/python/test_domain.py @@ -42,9 +42,10 @@ def test_validate_with_reason(): def test_c4k_build_should_update_fqdn(tmp_path): - project = Project(str(tmp_path), name="test-project") + project = Project(str(tmp_path), name="name") project_config = { "stage": "test", + "name": "name", "project_root_path": str(tmp_path), "module": "module", "build_dir_name": "target", @@ -62,7 +63,7 @@ def test_c4k_build_should_update_fqdn(tmp_path): grafana_cloud_user="user", grafana_cloud_password="password", ) - sut = C4kBuild(Build(project, project_config), project, project_config) + sut = C4kBuild(Build(project_config), project, project_config) sut.update_runtime_config("test.de", None, None) assert { @@ -88,9 +89,10 @@ def test_c4k_build_should_update_fqdn(tmp_path): def test_c4k_build_should_calculate_command(tmp_path): - project = Project(str(tmp_path), name="test-project") + project = Project(str(tmp_path), name="name") project_config = { "stage": "test", + "name": "name", "project_root_path": "", "module": "module", "build_dir_name": "target", @@ -102,17 +104,18 @@ def test_c4k_build_should_calculate_command(tmp_path): grafana_cloud_user="user", grafana_cloud_password="password", ) - sut = C4kBuild(Build(project, project_config), project, project_config) + sut = C4kBuild(Build(project_config), project, project_config) assert ( "c4k-module-standalone.jar " - + "/target/test-project/module/out_c4k_config.yaml " - + "/target/test-project/module/out_c4k_auth.yaml > " - + "/target/test-project/module/out_module.yaml" + + "/target/name/module/out_c4k_config.yaml " + + "/target/name/module/out_c4k_auth.yaml > " + + "/target/name/module/out_module.yaml" == sut.command() ) project_config = { "stage": "test", + "name": "name", "project_root_path": "", "module": "module", "build_dir_name": "target", @@ -125,12 +128,12 @@ def test_c4k_build_should_calculate_command(tmp_path): grafana_cloud_user="user", grafana_cloud_password="password", ) - sut = C4kBuild(Build(project, project_config), project, project_config) + sut = C4kBuild(Build(project_config), project, project_config) assert ( "c4k-executabel_name-standalone.jar " - + "/target/test-project/module/out_c4k_config.yaml " - + "/target/test-project/module/out_c4k_auth.yaml > " - + "/target/test-project/module/out_module.yaml" + + "/target/name/module/out_c4k_config.yaml " + + "/target/name/module/out_c4k_auth.yaml > " + + "/target/name/module/out_module.yaml" == sut.command() )