rhazdon/django-sonic-screwdriver

View on GitHub
django_sonic_screwdriver/git/git.py

Summary

Maintainability
A
0 mins
Test Coverage
from subprocess import call, check_output

from django_sonic_screwdriver.settings import api_settings
from django_sonic_screwdriver.version import version
from django_sonic_screwdriver.utils import shell
from django_sonic_screwdriver.git.decorators import git_available


GIT_OPTIONS = {
    "DEVELOPMENT": "development",
    "STAGING": "staging",
    "PRODUCTION": "production",
}


class Git:
    @staticmethod
    def create_git_version_tag(deploy_tag):
        if deploy_tag != "":
            deploy_tag += "-"
        return str(deploy_tag + "v" + version.get_version())

    @staticmethod
    @git_available
    def get_current_branch():
        current_branch = str(check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"]))
        return current_branch[2:][: (current_branch.__len__() - 5)]

    @staticmethod
    @git_available
    def get_latest_tag():
        latest_tag_hash = str(
            check_output(["git", "rev-list", "--tags", "--max-count=1"])
        )
        latest_tag = str(
            check_output(
                [
                    "git",
                    "describe",
                    "--tags",
                    latest_tag_hash[2:][: (latest_tag_hash.__len__() - 5)],
                ]
            )
        )
        return latest_tag[2:][: (latest_tag.__len__() - 5)]

    @staticmethod
    @git_available
    def check_existence_of_staging_tag_in_remote_repo():
        """
        This method will check, if the given tag exists as a staging
        tag in the remote repository.

        The intention is, that every tag, which should be deployed
        on a production environment, has to be deployed on a staging environment before.
        """
        staging_tag = Git.create_git_version_tag(api_settings.GIT_STAGING_PRE_TAG)

        command_git = "git ls-remote -t"
        command_awk = "awk '{print $2}'"
        command_cut_1 = "cut -d '/' -f 3"
        command_cut_2 = "cut -d '^' -f 1"
        command_sort = "sort -b -t . -k 1,1nr -k 2,2nr -k 3,3r -k 4,4r -k 5,5r"
        command_uniq = "uniq"

        command = (
            command_git
            + " | "
            + command_awk
            + " | "
            + command_cut_1
            + " | "
            + command_cut_2
            + " | "
            + command_sort
            + " | "
            + command_uniq
        )

        list_of_tags = str(check_output(command, shell=True))

        if staging_tag in list_of_tags:
            return True
        return False

    @staticmethod
    def __debug(command, dry=False):
        """
        This method will be called, if the debug mode is on.
        """
        if dry:
            command.append("--dry-run")
        shell.debug(command)

        if dry:
            call(command)
        exit(1)

    # Git Basic Methods
    @staticmethod
    @git_available
    def __git_tag(git_tag):
        """
        Create new tag.
        The function call will return 0 if the command success.
        """
        command = ["git", "tag", "-a", git_tag, "-m", "'" + git_tag + "'"]
        shell.msg("Create tag from version " + git_tag)

        if api_settings.DEBUG:
            Git.__debug(command, False)

        if not call(command):
            return True
        return False

    @staticmethod
    @git_available
    def __git_tag_gpg(git_tag):
        """
        Create new tag with GPG signature.
        The function call will return 0 if the command success.
        """
        command = ["git", "tag", "-s", git_tag, "-m", "'" + git_tag + "'"]
        shell.msg("Create signed tag version " + git_tag + " with GPG")

        if api_settings.DEBUG:
            Git.__debug(command, False)

        if not call(command):
            return True
        return False

    @staticmethod
    @git_available
    def __git_tag_push():
        """
        Push all tags.
        The function call will return 0 if the command success.
        """
        command = ["git", "push", "origin", "--tags"]
        shell.msg("Pushing tags...")

        if api_settings.DEBUG:
            Git.__debug(command, True)

        call(command)

    @staticmethod
    @git_available
    def __git_tag_delete(git_tag):
        """
        Delete last tag.
        The function call will return 0 if the command success.
        """
        command = ["git", "tag", "-d", "'" + git_tag + "'"]
        shell.msg("Delete tag.")

        if api_settings.DEBUG:
            Git.__debug(command, False)

        call(command)

    @git_available
    def __git_push(self):
        branch = self.get_current_branch
        command = ["git", "push", "-u", "origin", branch]
        shell.msg("Pushing branch " + branch + " to server...")

        if api_settings.DEBUG:
            Git.__debug(command, True)

        if not call(command):
            shell.success("Push success!")

    # Public Methods
    def tag(self, deploy_tag=""):
        """
        Function is public.
        Create a tag for current commit / branch.

        :param deploy_tag:
        :return:
        """
        if (
            api_settings.SECURE_TAGGING
            and deploy_tag == api_settings.GIT_ACTIVATE_PRE_TAG
        ):
            if self.check_existence_of_staging_tag_in_remote_repo():
                pass
            else:
                shell.fail(
                    "SECURE TAGGING is TRUE! That means, before you are able to "
                    "create a production tag, you need to deploy the software on "
                    "a staging environment."
                )
        self.__git_tag(self.create_git_version_tag(deploy_tag))

    def push_tags(self):
        """
        Function is public.
        Push tags.

        :return:
        """
        self.__git_tag_push()

    def tag_delete(self, tag):
        """
        Function is public.
        Push tags.

        :return:
        """
        if tag:
            self.__git_tag_delete(tag)
        self.__git_tag_delete(self.get_latest_tag())


git = Git()