def build(app_name: str, repository: str, app_config: dict) -> str: """Build the docker image of the last version of the app""" image_tag = git.get_last_tag(repository) Logger.info( {"tag": f"{app_name}@{image_tag}"}, "Application name and version", ) if has_docker_image(app_name, image_tag): Logger.info({}, "Docker image already built (skipped)") return image_tag commit_hash = git.get_commit_hash_from_tag(repository, image_tag) build_variables = app_config.get("docker", {}).get("build", {}).get("variables", {}) build_variables["COMMIT_HASH"] = commit_hash # Application build environment variables: builds_args = [] for key, value in build_variables.items(): builds_args.append(f"--build-arg {key}={value}") builds_args_str = " ".join(builds_args) command = f"docker build --tag {app_name}:{image_tag} {builds_args_str} {repository}" Logger.debug({"command": command}, "Docker build command") try: io.execute(command) except Exception as err: Logger.error({"err": err}, "Error while building Docker image") raise err return image_tag
def branch(repository_dir: str, branch_name: str) -> None: """Checkout a branch of a repository""" Logger.debug({"path": repository_dir}, "[git#branch] Repository path") exists = is_branch_existing(repository_dir, branch_name) io.execute(f'git checkout{"" if exists else " -b"} {branch_name}', repository_dir)
def branch(repository_dir, branch_name): """Checkout a branch of a repository""" Logger.debug({"path": repository_dir}, "[git#branch] Repository path") stdout = io.execute(f"git branch --list {branch_name}", repository_dir) exists = len(stdout) > 0 io.execute(f'git checkout{"" if exists else " -b"} {branch_name}', repository_dir)
def create_working_repository(app_name): """Checkout a branch of a repository""" # First, update the pristine repository for this app pristine_directory = update_pristine_repository(app_name) repository_dir = io.create_temporary_copy(pristine_directory, app_name) Logger.debug( {app_name, repository_dir}, "[git#create_working_directory] Created a working repository", ) return repository_dir
def update_pristine_repository(app_name): """Update the pristine repository of an application""" app_config = config.get_app_config(app_name) repository_dir = io.get_pristine_path(app_name) update_repository(repository_dir, app_config.get("git").get("origin")) Logger.debug( {app_name, repository_dir}, "[git#update_pristine_repository] Updated a pristine repository", ) return repository_dir
def create_working_repository(app_name: str, git_url: str) -> str: """Create a working copy of an app's repository""" pristine_directory = update_pristine_repository(app_name, git_url) repository_dir = io.create_temporary_copy(pristine_directory, app_name) Logger.debug( { "app": app_name, "repository": repository_dir }, "[git#create_working_directory] Created a working repository", ) return repository_dir
def update_pristine_repository(app_name: str, git_url: str) -> str: """Update the pristine repository of an application""" repository_dir = io.get_pristine_path(app_name) update_repository(repository_dir, git_url) Logger.debug( { "app": app_name, "repository": repository_dir }, "[git#update_pristine_repository] Updated a pristine repository", ) return repository_dir
def build(app_name, context): """Build the docker image of the last version of the app Example: > app_name = "my-app" > context = {"repository": "/path_to/my-app-doc", "commit_hash": "a2b3c4"} > build(app_name, context) """ repository = context["repository"] image_tag = git.get_last_tag(repository) Logger.info( {"tag": f"{app_name}@{image_tag}"}, "Application name and version", ) if has_docker_image(app_name, image_tag): Logger.info({}, "Docker image already built (skipped)") return image_tag app_config = config.get_app_config(app_name) commit_hash = context["commit_hash"] build_variables = app_config["build"]["variables"] # Application build environment variables: builds_args = [] for key, value in build_variables.items(): builds_args.append(f"--build-arg {key}={value}") builds_args.append(f"--build-arg COMMIT_HASH={commit_hash}") builds_args_str = " ".join(builds_args) command = f"docker build --tag {app_name}:{image_tag} {builds_args_str} {repository}" Logger.debug({"command": command}, "Docker build command") try: io.execute(command) except Exception as err: Logger.error({"err": err}, "Error while building Docker image") raise err return image_tag
def _differed_build(app_name: str): config_dir = None app_dir = None try: # Retrieve app's configuration config_dir = config.create_temporary_config_copy() config.change_environment(Configuration.get_config_default_branch(), config_dir) app_config = config.get_app_config(app_name, config_dir) Logger.debug( {"app": app_name, "config_directory": config_dir}, "[/api/builds/:app] Application's configuration retrieved", ) # Retrieve app's repository app_dir = git.create_working_repository(app_name, app_config["git"]["origin"]) git.branch(app_dir, app_config["workflow"][0]) Logger.debug( {"app": app_name, "working_directory": app_dir}, "[/api/builds/:app] Application's repository retrieved", ) try: # Create a new tag version = app.get_version(app_dir) git_tag = git.tag(app_dir, version) Logger.debug( {"app": app_name, "tag": git_tag}, "[/api/builds/:app] New tag created", ) except Exception as err: # The tag may already exist Logger.warn( {"app": app_name, "err": err}, "[/api/builds/:app] Error while tagging the app" ) # Build and publish the new docker image image_tag = docker.build(app_name, app_dir, app_config) Logger.debug( {"app": app_name, "image": image_tag}, "[/api/builds/:app] Docker image created" ) docker.push(app_name, image_tag, app_config) Logger.debug( {"app": app_name, "image": image_tag}, "[/api/builds/:app] Docker image published on registry", ) # Send the new tag to git git.push(app_dir) Logger.debug({"app": app_name}, "[/api/builds/:app] Tag pushed to Git") except Exception as err: Logger.error( {"app": app_name, "err": err}, "[/api/builds/:app] Error while tagging and building the app", ) # Clean up temporary directories try: if config_dir is not None: io.remove(config_dir) if app_dir is not None: io.remove(app_dir) except Exception as err: Logger.error({"app": app_name, "err": err}, "[/api/builds/:app] Error during cleanup")
def test_logger_debug_with_no_context(self, logging_mock): Logger.debug(message="Found user") logging_mock.debug.assert_called_once_with("Found user")
def test_logger_debug(self, logging_mock): Logger.debug({"user_id": 1234}, "Found user") logging_mock.debug.assert_called_once_with("%s %s", "Found user", '{"user_id": 1234}')