integrate release as mixin
This commit is contained in:
parent
26b76a045a
commit
d670605d37
7 changed files with 133 additions and 53 deletions
|
@ -45,7 +45,7 @@ classDiagram
|
|||
|
||||
Devops *-- "0..1" Image: spcialized_builds
|
||||
Devops *-- "0..1" C4k: spcialized_builds
|
||||
Devops *-- Release: release
|
||||
Devops *-- "0..1" Release: mixins
|
||||
C4k *-- DnsRecord
|
||||
Release *-- "0..1" ReleaseContext
|
||||
|
||||
|
|
|
@ -4,13 +4,20 @@ from typing import List, TypedDict
|
|||
import logging
|
||||
import deprecation
|
||||
|
||||
|
||||
def filter_none(list_to_filter):
|
||||
return [x for x in list_to_filter if x is not None]
|
||||
|
||||
|
||||
class BuildType(Enum):
|
||||
IMAGE = 0
|
||||
C4K = 1
|
||||
|
||||
|
||||
class MixinType(Enum):
|
||||
RELEASE = 0
|
||||
|
||||
|
||||
class Validateable:
|
||||
def __validate_is_not_none__(self, field_name: str) -> List[str]:
|
||||
value = self.__dict__[field_name]
|
||||
|
@ -32,9 +39,10 @@ class Validateable:
|
|||
|
||||
def throw_if_invalid(self):
|
||||
if not self.is_valid():
|
||||
issues = '\n'.join(self.validate())
|
||||
issues = "\n".join(self.validate())
|
||||
raise ValueError(f"Invalid Validateable: {issues}")
|
||||
|
||||
|
||||
class DnsRecord(Validateable):
|
||||
def __init__(self, fqdn, ipv4=None, ipv6=None):
|
||||
self.fqdn = fqdn
|
||||
|
@ -50,13 +58,19 @@ class DnsRecord(Validateable):
|
|||
|
||||
|
||||
class Devops(Validateable):
|
||||
def __init__(self, input: dict, specialized_builds: dict[BuildType, Validateable]):
|
||||
self.stage = input.get('stage')
|
||||
self.project_root_path = input.get('project_root_path')
|
||||
self.module = input.get('module')
|
||||
self.name = input.get('name', self.module)
|
||||
self.build_dir_name = input.get('build_dir_name', 'target')
|
||||
self.specialized_builds=specialized_builds
|
||||
def __init__(
|
||||
self,
|
||||
input: dict,
|
||||
specialized_builds: dict[BuildType, Validateable],
|
||||
mixins: dict[MixinType, Validateable],
|
||||
):
|
||||
self.stage = input.get("stage")
|
||||
self.project_root_path = input.get("project_root_path")
|
||||
self.module = input.get("module")
|
||||
self.name = input.get("name", self.module)
|
||||
self.build_dir_name = input.get("build_dir_name", "target")
|
||||
self.specialized_builds = specialized_builds
|
||||
self.mixins = mixins
|
||||
|
||||
def build_path(self):
|
||||
path = [self.project_root_path, self.build_dir_name, self.name, self.module]
|
||||
|
@ -71,6 +85,9 @@ class Devops(Validateable):
|
|||
if self.specialized_builds:
|
||||
for build in self.specialized_builds:
|
||||
result += self.specialized_builds[build].validate()
|
||||
if self.mixins:
|
||||
for mixin in self.mixins:
|
||||
result += self.mixins[mixin].validate()
|
||||
return result
|
||||
|
||||
def __put__(self, key, value):
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import deprecation
|
||||
from enum import Enum
|
||||
from typing import List
|
||||
from .common import Devops, BuildType
|
||||
from .common import Devops, BuildType, MixinType
|
||||
from .image import Image
|
||||
from .c4k import C4k
|
||||
from .release import Release, ReleaseContext
|
||||
|
||||
|
||||
class DevopsFactory:
|
||||
def __init__(self):
|
||||
|
@ -11,13 +13,20 @@ class DevopsFactory:
|
|||
|
||||
def build_devops(self, input) -> Devops:
|
||||
build_types = self.__parse_build_types__(input["build_types"])
|
||||
mixin_types = self.__parse_mixin_types__(input["mixin_types"])
|
||||
|
||||
specialized_builds = {}
|
||||
if BuildType.IMAGE in build_types:
|
||||
specialized_builds[BuildType.IMAGE] = Image(input)
|
||||
if BuildType.C4K in build_types:
|
||||
specialized_builds[BuildType.C4K] = C4k(input)
|
||||
|
||||
devops = Devops(input, specialized_builds=specialized_builds)
|
||||
mixins = {}
|
||||
if MixinType.RELEASE in mixin_types:
|
||||
release_context = ReleaseContext(input)
|
||||
mixins[MixinType.RELEASE] = Release(input, release_context=release_context)
|
||||
|
||||
devops = Devops(input, specialized_builds=specialized_builds, mixins=mixins)
|
||||
|
||||
devops.throw_if_invalid()
|
||||
|
||||
|
@ -31,3 +40,9 @@ class DevopsFactory:
|
|||
for build_type in build_types:
|
||||
result += [BuildType[build_type]]
|
||||
return result
|
||||
|
||||
def __parse_mixin_types__(self, mixin_types: List[str]) -> List[MixinType]:
|
||||
result = []
|
||||
for mixin_type in mixin_types:
|
||||
result += [MixinType[mixin_type]]
|
||||
return result
|
||||
|
|
|
@ -6,18 +6,21 @@ from .common import (
|
|||
Devops,
|
||||
)
|
||||
|
||||
|
||||
class ReleaseType(Enum):
|
||||
MAJOR = 0
|
||||
MINOR = 1
|
||||
PATCH = 2
|
||||
SNAPSHOT = 3
|
||||
BUMP = None
|
||||
NONE = 15
|
||||
|
||||
|
||||
class EnvironmentKeys(Enum):
|
||||
DDADEVOPS_RELEASE_TYPE = 0
|
||||
|
||||
class Version():
|
||||
|
||||
class Version(Validateable):
|
||||
def __init__(self, path: Path, version_list: list):
|
||||
self.path = path
|
||||
self.version_list = version_list
|
||||
|
@ -62,11 +65,25 @@ class Version():
|
|||
bump_version.increment(ReleaseType.BUMP)
|
||||
return bump_version
|
||||
|
||||
|
||||
class ReleaseContext(Validateable):
|
||||
def __init__(self, release_type: ReleaseType | None, version: Version, current_branch: str):
|
||||
self.release_type = release_type
|
||||
self.version = version
|
||||
self.current_branch = current_branch
|
||||
def __init__(
|
||||
self,
|
||||
input: dict,
|
||||
):
|
||||
self.release_type = ReleaseType[input.get("release_type", "SNAPSHOT")]
|
||||
self.release_current_version = input.get("release_current_version")
|
||||
self.release_current_branch = input.get("release_current_branch")
|
||||
self.version = self.__version_from_str__()
|
||||
|
||||
# TODO: mv version parsing to version
|
||||
def __version_from_str__(self):
|
||||
if not self.release_current_version:
|
||||
return
|
||||
version_parsed = []
|
||||
for x in self.release_current_version.split("."):
|
||||
version_parsed += [int(x)]
|
||||
return Version("unused", version_parsed)
|
||||
|
||||
def release_version(self) -> Version:
|
||||
return self.version.create_release_version(self.release_type)
|
||||
|
@ -77,30 +94,32 @@ class ReleaseContext(Validateable):
|
|||
def validate(self):
|
||||
result = []
|
||||
result += self.__validate_is_not_empty__("release_type")
|
||||
result += self.__validate_is_not_empty__("version")
|
||||
result += self.__validate_is_not_empty__("current_branch")
|
||||
result += self.__validate_is_not_empty__("release_current_version")
|
||||
result += self.__validate_is_not_empty__("release_current_branch")
|
||||
if self.version:
|
||||
result += self.version.validate()
|
||||
return result
|
||||
|
||||
def validate_branch(self, main_branch: str):
|
||||
result = []
|
||||
if self.release_type is not None and main_branch != self.current_branch:
|
||||
if (
|
||||
self.release_type is not None
|
||||
and self.release_type != ReleaseType.NONE
|
||||
and main_branch != self.release_current_branch
|
||||
):
|
||||
result.append(f"Releases are allowed only on {main_branch}")
|
||||
return result
|
||||
|
||||
|
||||
class Release(Validateable):
|
||||
def __init__(
|
||||
self,
|
||||
devops: Devops,
|
||||
main_branch: str,
|
||||
config_file: str,
|
||||
input: dict,
|
||||
release_context: ReleaseContext,
|
||||
):
|
||||
self.devops = devops
|
||||
self.main_branch = main_branch
|
||||
self.config_file = config_file
|
||||
self.release_context: ReleaseContext | None = None
|
||||
|
||||
def set_release_context(self, set_release_context: ReleaseContext):
|
||||
self.release_context = set_release_context
|
||||
self.release_main_branch = input.get("release_main_branch", "main")
|
||||
self.release_config_file = input.get("release_config_file", "project.clj")
|
||||
self.release_context = release_context
|
||||
|
||||
def release_version(self):
|
||||
return self.release_context.release_version()
|
||||
|
@ -108,14 +127,12 @@ class Release(Validateable):
|
|||
def bump_version(self):
|
||||
return self.release_context.bump_version()
|
||||
|
||||
|
||||
def validate(self):
|
||||
result = []
|
||||
result += self.__validate_is_not_empty__("main_branch")
|
||||
result += self.__validate_is_not_empty__("config_file")
|
||||
result += self.__validate_is_not_empty__("release_main_branch")
|
||||
result += self.__validate_is_not_empty__("release_config_file")
|
||||
result += self.__validate_is_not_empty__("release_context")
|
||||
if self.release_context is not None:
|
||||
result += self.release_context.validate()
|
||||
result += self.release_context.validate_branch(self.main_branch)
|
||||
result += self.release_context.validate_branch(self.release_main_branch)
|
||||
return result
|
||||
|
|
@ -22,12 +22,13 @@ def test_devops_factory():
|
|||
"module": "test_image",
|
||||
"project_root_path": "../../..",
|
||||
"build_types": ["IMAGE"],
|
||||
"mixin_types": [],
|
||||
"image_dockerhub_user": "dockerhub_user",
|
||||
"image_dockerhub_password": "dockerhub_password",
|
||||
"image_tag": "docker_image_tag",
|
||||
}
|
||||
)
|
||||
assert sut != None
|
||||
assert sut is not None
|
||||
|
||||
sut = DevopsFactory().build_devops(
|
||||
{
|
||||
|
@ -36,8 +37,26 @@ def test_devops_factory():
|
|||
"module": "test_image",
|
||||
"project_root_path": "../../..",
|
||||
"build_types": ["C4K"],
|
||||
"mixin_types": [],
|
||||
"c4k_grafana_cloud_user": "user",
|
||||
"c4k_grafana_cloud_password": "password",
|
||||
}
|
||||
)
|
||||
assert sut != None
|
||||
assert sut 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_config_file": "project.clj",
|
||||
"release_type": "NONE",
|
||||
"release_current_version": "1.0.0",
|
||||
"release_current_branch": "my_feature",
|
||||
}
|
||||
)
|
||||
assert sut is not None
|
||||
|
|
|
@ -9,14 +9,20 @@ def devops_config(overrides: dict) -> dict:
|
|||
"project_root_path": "../../..",
|
||||
"build_dir_name": "target",
|
||||
"build_types": ["IMAGE", "C4K"],
|
||||
"mixin_types": ["RELEASE"],
|
||||
"image_dockerhub_user": "dockerhub_user",
|
||||
"image_dockerhub_password": "dockerhub_password",
|
||||
"image_tag": "image_tag",
|
||||
'c4k_config': {},
|
||||
"c4k_config": {},
|
||||
"c4k_grafana_cloud_user": "user",
|
||||
"c4k_grafana_cloud_password": "password",
|
||||
"c4k_grafana_cloud_url": "https://prometheus-prod-01-eu-west-0.grafana.net/api/prom/push",
|
||||
'c4k_auth': {},
|
||||
"c4k_auth": {},
|
||||
"release_main_branch": "main",
|
||||
"release_config_file": "project.clj",
|
||||
"release_type": "NONE",
|
||||
"release_current_version": "1.0.0",
|
||||
"release_current_branch": "my_feature",
|
||||
}
|
||||
input = default.copy()
|
||||
input.update(overrides)
|
||||
|
|
|
@ -5,6 +5,7 @@ from src.main.python.ddadevops.domain.common import (
|
|||
DnsRecord,
|
||||
Devops,
|
||||
BuildType,
|
||||
MixinType,
|
||||
)
|
||||
from src.main.python.ddadevops.domain import (
|
||||
Version,
|
||||
|
@ -13,7 +14,8 @@ from src.main.python.ddadevops.domain import (
|
|||
ReleaseContext,
|
||||
)
|
||||
from src.main.python.ddadevops.domain.image import Image
|
||||
from .test_helper import build_devops
|
||||
from .test_helper import build_devops, devops_config
|
||||
|
||||
|
||||
def test_version(tmp_path: Path):
|
||||
version = Version(tmp_path, [1, 2, 3])
|
||||
|
@ -48,22 +50,26 @@ def test_version(tmp_path: Path):
|
|||
|
||||
|
||||
def test_release_context(tmp_path):
|
||||
version = Version(tmp_path, [1, 2, 3])
|
||||
release = ReleaseContext(ReleaseType.MINOR, version, "main")
|
||||
|
||||
release_version = release.release_version()
|
||||
assert release_version.get_version_string() in "1.3.0"
|
||||
|
||||
bump_version = release.bump_version()
|
||||
assert bump_version.get_version_string() in "1.3.1-SNAPSHOT"
|
||||
sut = ReleaseContext(
|
||||
devops_config(
|
||||
{
|
||||
"release_type": "MINOR",
|
||||
"release_current_version": "1.2.3",
|
||||
"release_current_branch": "main",
|
||||
}
|
||||
)
|
||||
)
|
||||
assert sut.release_version().get_version_string() == "1.3.0"
|
||||
assert sut.bump_version().get_version_string() == "1.3.1-SNAPSHOT"
|
||||
|
||||
|
||||
def test_release(tmp_path):
|
||||
devops = build_devops({})
|
||||
sut = Release(devops, "main", "config_file.json")
|
||||
assert not sut.is_valid()
|
||||
|
||||
sut.set_release_context(
|
||||
ReleaseContext(ReleaseType.MINOR, Version("id", [1, 2, 3]), "main")
|
||||
sut = build_devops(
|
||||
{
|
||||
"release_type": "MINOR",
|
||||
"release_current_version": "1.2.3",
|
||||
"release_current_branch": "main",
|
||||
}
|
||||
)
|
||||
assert sut.mixins[MixinType.RELEASE]
|
||||
assert sut.is_valid()
|
||||
|
|
Loading…
Reference in a new issue