mobiusbyte/bumpit

View on GitHub
bumpit/core/vcs.py

Summary

Maintainability
A
0 mins
Test Coverage
import os
from dataclasses import dataclass


@dataclass
class GitSettings:
    author: str
    apply_tag: bool
    tag_format: str
    auto_remote_push: bool


class Git:
    def __init__(self, dry_run, settings, logger, command_executor=None):
        self._dry_run = dry_run
        self._author = settings.author
        self._apply_tag = settings.apply_tag
        self._tag_format = self._parse_tag_format(settings.tag_format)
        self._auto_remote_push = settings.auto_remote_push
        self._logger = logger
        self._command_executor = command_executor or os.system

    def update(self, current_version, bumped_version, base_branch):
        self._git_commit(current_version, bumped_version)
        self._git_tag(current_version, bumped_version)
        self._git_push(base_branch)

    def _git_commit(self, current_version, bumped_version):
        self._execute_command("git add .")
        self._execute_command(
            f"git commit --author '{self._author}' "
            f"-m '{self._bump_message(current_version, bumped_version)}'"
        )

    def _git_tag(self, current_version, bumped_version):
        if not self._apply_tag:
            self._logger.info("Skipped tagging...")
            return

        tag_command_format = (
            f"git tag "
            f"-a '{self._tag_format}' "
            f"-m '{self._bump_message(current_version, bumped_version)}'"
        )
        tag_command = tag_command_format.format(version=bumped_version)

        self._execute_command(tag_command)

    def _git_push(self, base_branch):
        if self._auto_remote_push:
            return self._execute_command(f"git push origin {base_branch} --tags")
        else:
            self._logger.info("Skipped pushing changes to remote...")

    def _bump_message(self, current_version, bumped_version):
        return f"Bumped version from {current_version} → {bumped_version}."

    def _execute_command(self, command):
        if self._dry_run:
            self._logger.info(f"[DRY-RUN] Ran `{command}`")
        else:
            if self._command_executor(command) != 0:
                raise Exception(f"Failed to execute {command}.")

            self._logger.info(f"[OK] {command}")

    @staticmethod
    def _parse_tag_format(tag_format):
        if "{version}" not in tag_format:
            raise ValueError(
                f"Invalid tag_format '{tag_format}'. "
                f"Value must include the string `{{version}}`."
            )
        return tag_format