Skip to content

Commit

Permalink
CH-157 Move manifest management code into its own file
Browse files Browse the repository at this point in the history
  • Loading branch information
condar-metacell committed Nov 1, 2024
1 parent dca0eae commit 4b768ef
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 98 deletions.
16 changes: 1 addition & 15 deletions tools/deployment-cli-tools/ch_cli_tools/common_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,4 @@ def to_dict(self) -> dict:
'version': self.version,
'inferred': self.inferred,
'templates': [str(template) for template in self.templates],
}

@classmethod
def migrate(cls, data: dict) -> tuple[dict, bool]:
data_copy = copy.deepcopy(data)
update_manifest = False

if data_copy['version'] < '2':
update_manifest = True
data_copy['templates'] = [
template if template != 'django-app' else 'django-fastapi'
for template in data_copy['templates']
]

return data_copy, update_manifest
}
135 changes: 135 additions & 0 deletions tools/deployment-cli-tools/ch_cli_tools/manifest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import abc
import copy
import logging
import pathlib
from typing import Iterable
from ruamel.yaml.error import YAMLError
from .common_types import CloudHarnessManifest, TemplateType
from .utils import load_yaml, save_yaml


def get_manifest(app_path: pathlib.Path) -> CloudHarnessManifest:
manifest_file = app_path / '.ch-manifest'

try:
manifest_data = load_yaml(manifest_file)
return CloudHarnessManifest.from_dict(manifest_data)
except (FileNotFoundError, YAMLError):
logging.info(f'Could not load manifest file {manifest_file}, inferring manifest from app structure...')
manifest = CloudHarnessManifest(
app_name=app_path.name,
inferred=True,
templates=infer_templates(app_path),
)
save_yaml(manifest_file, manifest.to_dict())
return manifest


def load_manifest(manifest_file: pathlib.Path) -> dict:
manifest_data = load_yaml(manifest_file)
migrated_data = migrate_manifest_data(manifest_data)

if manifest_data != migrated_data:
save_yaml(manifest_file, migrated_data)

return migrated_data


def migrate_manifest_data(data: dict) -> dict:
data = copy.deepcopy(data)
data_version = data['version']
migrations = [
migration for migration in _MIGRATIONS_LIST
if data_version < migration.change_version
]

for migration in migrations:
migration.migrate(data)

return data


def infer_templates(app_path: pathlib.Path) -> list[str]:
return [
TemplateType.BASE,
*infer_webapp_template(app_path),
*infer_server_template(app_path),
*infer_database_template(app_path),
]


def infer_webapp_template(app_path: pathlib.Path) -> Iterable[str]:
frontend_path = app_path / 'frontend'
if frontend_path.exists():
yield TemplateType.WEBAPP


def infer_server_template(app_path: pathlib.Path) -> Iterable[str]:
backend_path = app_path / 'backend'
manage_path = backend_path / 'manage.py'

if manage_path.exists():
yield from infer_django_template(backend_path)
return

server_path = app_path / 'server'
if server_path.exists() or backend_path.exists():
yield TemplateType.FLASK_SERVER


def infer_django_template(backend_path: pathlib.Path) -> Iterable[str]:
requirements_path = backend_path / 'requirements.txt'
requirements = requirements_path.read_text()

if 'django-ninja' in requirements:
yield TemplateType.DJANGO_NINJA
else:
yield TemplateType.DJANGO_FASTAPI


def infer_database_template(app_path: pathlib.Path) -> Iterable[str]:
values_file = app_path / 'deploy' / 'values.yaml'

try:
values_data = load_yaml(values_file)
database_config = values_data['harness']['database']
if not database_config['auto']:
return

database_type = database_config['type']
database_type_to_template_map = {
'mongo': TemplateType.DB_MONGO,
'neo4j': TemplateType.DB_NEO4J,
'postgres': TemplateType.DB_POSTGRES,
}

if database_type in database_type_to_template_map:
yield database_type_to_template_map[database_type]

except(FileNotFoundError, YAMLError, KeyError):
pass


class ManifestMigration(abc.ABC):
@property
@abc.abstractmethod
def change_version(self) -> str:
...

@abc.abstractmethod
def migrate(data: dict) -> None:
...


class NameChangeFromDjangoAppToDjangoFastapi(ManifestMigration):
change_version = '2'

def migrate(data):
data['templates'] = [
template if template != 'django-app' else 'django-fastapi'
for template in data['templates']
]

_MIGRATIONS_LIST: list[ManifestMigration] = [
NameChangeFromDjangoAppToDjangoFastapi(),
]
87 changes: 4 additions & 83 deletions tools/deployment-cli-tools/harness-generate
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import pathlib
import shutil
import logging
from typing import Callable, Optional
from ruamel.yaml.error import YAMLError

from ch_cli_tools.openapi import LIB_NAME, generate_openapi_from_ninja_schema, generate_python_client, generate_server, generate_fastapi_server, \
get_dependencies, generate_ts_client, generate_model
from ch_cli_tools.utils import copymergedir, load_yaml, save_yaml
from ch_cli_tools.common_types import CloudHarnessManifest, TemplateType
from ch_cli_tools.utils import copymergedir
from ch_cli_tools.common_types import TemplateType
from ch_cli_tools.manifest import get_manifest


def main():
Expand Down Expand Up @@ -152,7 +152,7 @@ def generate_servers(
"""
Generates server stubs
"""
openapi_files = get_openapi_file_paths(root_path)
openapi_files = [path for path in root_path.glob('applications/*/api/*.yaml')]

for openapi_file in openapi_files:
app_path = openapi_file.parent.parent
Expand Down Expand Up @@ -207,10 +207,6 @@ def generate_clients(
aggregate_packages(client_src_path, client_lib_name)


def get_openapi_file_paths(root_path: pathlib.Path) -> list[pathlib.Path]:
return [path for path in root_path.glob('applications/*/api/*.yaml')]


def aggregate_packages(client_source_path: pathlib.Path, lib_name=LIB_NAME):
client_source_path.mkdir(parents=True, exist_ok=True)

Expand Down Expand Up @@ -278,80 +274,5 @@ def aggregate_packages(client_source_path: pathlib.Path, lib_name=LIB_NAME):
shutil.rmtree(temp_module_path)


def get_manifest(app_path: pathlib.Path) -> CloudHarnessManifest:
manifest_file = app_path / '.ch-manifest'

try:
manifest_data = load_yaml(manifest_file)
manifest_data, update_manifest = CloudHarnessManifest.migrate(manifest_data)
if update_manifest:
save_yaml(manifest_file, manifest_data)
manifest = CloudHarnessManifest.from_dict(manifest_data)
except (FileNotFoundError, YAMLError):
logging.info(f'Could not find manifest file {manifest_file}, inferring manifest from app structure...')
manifest = CloudHarnessManifest(
app_name=app_path.name,
inferred=True,
templates=infer_templates(app_path),
)
save_yaml(manifest_file, manifest.to_dict())

return manifest


def infer_templates(app_path: pathlib.Path) -> list[str]:
templates = [TemplateType.BASE]

infer_webapp_template(app_path, templates)
infer_server_template(app_path, templates)
infer_database_template(app_path, templates)

return templates


def infer_webapp_template(app_path: pathlib.Path, templates: list[str]) -> None:
frontend_path = app_path / 'frontend'
if frontend_path.exists():
templates.append(TemplateType.WEBAPP)


def infer_server_template(app_path: pathlib.Path, templates: list[str]) -> None:
backend_path = app_path / 'backend'
manage_path = backend_path / 'manage.py'

if manage_path.exists():
requirements_path = backend_path / 'requirements.txt'
requirements = requirements_path.read_text()
if 'ninja' in requirements:
templates.append(TemplateType.DJANGO_NINJA)
else:
templates.append(TemplateType.DJANGO_FASTAPI)
return

server_path = app_path / 'server'
if server_path.exists() or backend_path.exists():
templates.append(TemplateType.FLASK_SERVER)


def infer_database_template(app_path: pathlib.Path, templates: list[str]) -> None:
values_file = app_path / 'deploy' / 'values.yaml'

try:
values_data = load_yaml(values_file)
database_config = values_data['harness']['database']
if not database_config['auto']:
return

database_type = database_config['type']
if database_type == 'mongo':
templates.append(TemplateType.DB_MONGO)
if database_type == 'neo4j':
templates.append(TemplateType.DB_NEO4J)
if database_type == 'postgres':
templates.append(TemplateType.DB_POSTGRES)
except (FileNotFoundError, YAMLError, KeyError):
pass


if __name__ == "__main__":
main()

0 comments on commit 4b768ef

Please sign in to comment.