JrGoodle/clowder

View on GitHub
clowder/cli/prune.py

Summary

Maintainability
A
0 mins
Test Coverage
A
97%
"""Clowder command line prune controller

.. codeauthor:: Joe DeCapo <joe@polka.cat>

"""

from typing import List

from clowder.util.app import Argument, BoolArgument, MutuallyExclusiveArgumentGroup, Subcommand
from clowder.util.connectivity import network_connection_required
from clowder.util.console import CONSOLE

from clowder.controller import (
    CLOWDER_CONTROLLER,
    print_clowder_name,
    print_clowder_repo_status,
    valid_clowder_yaml_required
)
from clowder.config import Config
from clowder.util.error import CommandArgumentError

from .util import ProjectsArgument


class PruneCommand(Subcommand):
    class Meta:
        name = 'prune'
        help = 'Prune branches'
        args = [
            Argument('branch', help='name of branch to remove'),
            ProjectsArgument('projects and groups to prune'),
            BoolArgument('--force', '-f', help='force prune branches')
        ]
        mutually_exclusive_args = [
            MutuallyExclusiveArgumentGroup(
                args=[
                    BoolArgument('--all', '-a', help='prune local and remote branches'),
                    BoolArgument('--remote', '-r', help='prune remote branches')
                ]
            )
        ]

    @valid_clowder_yaml_required
    @print_clowder_name
    @print_clowder_repo_status
    def run(self, args) -> None:
        if args.all:
            self._prune_all(args)
            return

        if args.remote:
            self._prune_remote(args)
            return

        self._prune_impl(args.projects, args.branch, force=args.force, local=True)

    @network_connection_required
    def _prune_all(self, args) -> None:
        """clowder prune all command"""

        self._prune_impl(args.projects, args.branch, force=args.force, local=True, remote=True)

    @network_connection_required
    def _prune_remote(self, args) -> None:
        """clowder prune remote command"""

        self._prune_impl(args.projects, args.branch, remote=True)

    @staticmethod
    def _prune_impl(project_names: List[str], branch: str, force: bool = False,
                    local: bool = False, remote: bool = False) -> None:
        """Prune branches

        :param List[str] project_names: Project names to prune
        :param str branch: Branch to prune
        :param bool force: Force delete branch
        :param bool local: Delete local branch
        :param bool remote: Delete remote branch
        """

        projects = Config().process_projects_arg(project_names)
        projects = CLOWDER_CONTROLLER.filter_projects(CLOWDER_CONTROLLER.projects, projects)

        CLOWDER_CONTROLLER.validate_projects_state(projects)

        local_branch_exists = CLOWDER_CONTROLLER.project_has_local_branch(projects, branch)
        remote_branch_exists = CLOWDER_CONTROLLER.project_has_remote_branch(projects, branch)

        if local and remote:
            branch_exists = local_branch_exists or remote_branch_exists
            if not branch_exists:
                CONSOLE.stdout(' - No local or remote branches to prune')
                return
            CONSOLE.stdout(' - Prune local and remote branches\n')
        elif remote:
            if not remote_branch_exists:
                CONSOLE.stdout(' - No remote branches to prune')
                return
            CONSOLE.stdout(' - Prune remote branches\n')
        elif local:
            if not local_branch_exists:
                CONSOLE.stdout(' - No local branches to prune')
                return
            CONSOLE.stdout(' - Prune local branches\n')
        else:
            raise CommandArgumentError('local and remote are both false, but at least one should be true')

        for project in projects:
            CONSOLE.stdout(project.status())
            project.prune(branch, force=force, local=local, remote=remote)