# -*- coding: utf-8 -*- from __future__ import annotations import datetime from invoke import task from hotpocket_workspace_tools import get_workspace_mode, WorkspaceMode class DockerBuildContext: def __init__(self, /, target='deployment', version=None, build='01', machine=None, ): self._target = target self._version = version self._build = build self._image_arch = None self._node_arch = None def __enter__(self, *args, **kwargs): return self def __exit__(self, *args, **kwargs): pass @property def target(self) -> str: return self._target @property def version(self) -> str: return self._version or datetime.date.today().strftime('%Y%m%d') @property def build(self) -> str: return self._build.zfill(2) @property def image_arch(self) -> str: return self._image_arch @property def node_arch(self) -> str: return self._node_arch @property def tag(self) -> str: return '{target}-{version}-{build}'.format( target=self.target, version=self.version, build=self.build, ) WORKSPACE_MODE = get_workspace_mode() ALL_SERVICES = ['backend', 'packages'] def _run_in_service(ctx, service, command, **kwargs): match WORKSPACE_MODE: case WorkspaceMode.DOCKER: return ctx.run( f'docker compose run --rm -it {service}-management {command}', ) case WorkspaceMode.METAL: with ctx.cd(f'services/{service}'): ctx.run(f'direnv exec . {command}') def _get_version(ctx, service): with ctx.cd(f'services/{service}'): run_result = ctx.run('poetry version -s', hide='out') return run_result.stdout.strip() def _get_head_sha(ctx): run_result = ctx.run('git rev-parse HEAD', hide='out') return run_result.stdout.strip() @task def clean(ctx, service): _run_in_service(ctx, service, 'inv clean') @task def test(ctx, service): _run_in_service(ctx, service, 'inv test') @task def lint(ctx, service): _run_in_service(ctx, service, 'inv lint') @task def typecheck(ctx, service): _run_in_service(ctx, service, 'inv typecheck') @task def shell(ctx, service): assert WORKSPACE_MODE == WorkspaceMode.DOCKER, ( 'Just `cd services/{service}` ;)' ) _run_in_service(ctx, service, '/bin/bash') @task def django_shell(ctx, service): _run_in_service(ctx, service, 'inv django-shell') @task def build(ctx, service, context=None, builder=None, push=False, target='deployment', version=None, build='01', image_tag=None, machine=None, platform=None, ): image_tag = image_tag or '{target}.{{short_sha}}'.format(target=target) short_sha = _get_head_sha(ctx)[:8] image_tag = image_tag.format( short_sha=short_sha, ) with DockerBuildContext(target, version, build, machine) as docker_build_ctx: # noqa: E501 commandline = [ 'docker', ( f'--context {context}' if context is not None else '' ), 'buildx build', ( f'--builder {builder}' if builder is not None else '' ), ( '--push' if push is True else '' ), ( f'--platform {platform}' if platform is not None else '' ), f'-t docker-hosted.nexus.bthlabs.pl/hotpocket/{service}:{docker_build_ctx.tag}', # noqa: E501 f'-f services/{service}/Dockerfile', f'--build-arg IMAGE_ID={image_tag}', f'--target {docker_build_ctx.target}', 'services/', ] ctx.run(' '.join(commandline)) @task def publish(ctx, service, context=None, target='deployment', version=None, build='01', machine=None, ): with DockerBuildContext(target, version, build, machine) as docker_build_ctx: # noqa: E501 commandline = [ 'docker', ( f'--context {context}' if context is not None else '' ), 'push', f'docker-hosted.nexus.bthlabs.pl/hotpocket/{service}:{docker_build_ctx.tag}', # noqa: E501 ] ctx.run(' '.join(commandline)) @task def ci(ctx, service): _run_in_service(ctx, service, 'inv ci') @task def setup(ctx, service=None): services_to_setup = [] services_to_setup = [*ALL_SERVICES] if service is not None: services_to_setup = [service] for service_to_setup in services_to_setup: _run_in_service(ctx, service_to_setup, 'inv setup') @task def install(ctx, service=None): services_to_setup = [] services_to_setup = [*ALL_SERVICES] if service is not None: services_to_setup = [service] for service_to_setup in services_to_setup: _run_in_service(ctx, service_to_setup, 'poetry install') @task def lock(ctx, service): _run_in_service(ctx, service, 'poetry lock --no-update') @task def start_cloud(ctx): ctx.run('docker compose -f docker-compose-cloud.yaml up') @task def start_web(ctx, service): _run_in_service(ctx, service, 'inv start-web') @task def start_celery_worker(ctx, service): _run_in_service(ctx, service, 'inv start-worker') @task def start_celery_beat(ctx, service): _run_in_service(ctx, service, 'inv start-beat') @task def start_app(ctx, service, app): _run_in_service(ctx, service, f'inv start-{app}')