Implement unittests
This commit is contained in:
		@ -8,42 +8,34 @@ from semver.logger import logger
 | 
			
		||||
class SCM(ABC):
 | 
			
		||||
    @abstractmethod
 | 
			
		||||
    def get_tag_version(self) -> str:
 | 
			
		||||
        raise NotImplementedError
 | 
			
		||||
        raise NotImplementedError()
 | 
			
		||||
 | 
			
		||||
    @abstractmethod
 | 
			
		||||
    def get_branch(self) -> str:
 | 
			
		||||
        raise NotImplementedError
 | 
			
		||||
        raise NotImplementedError()
 | 
			
		||||
 | 
			
		||||
    @abstractmethod
 | 
			
		||||
    def get_merge_branch(self) -> Union[str, None]:
 | 
			
		||||
        raise NotImplementedError
 | 
			
		||||
        raise NotImplementedError()
 | 
			
		||||
 | 
			
		||||
    @abstractmethod
 | 
			
		||||
    def commit_and_push(self, branch: str) -> None:
 | 
			
		||||
        raise NotImplementedError
 | 
			
		||||
        raise NotImplementedError()
 | 
			
		||||
 | 
			
		||||
    @abstractmethod
 | 
			
		||||
    def tag_version(self, version: str) -> None:
 | 
			
		||||
        raise NotImplementedError
 | 
			
		||||
        raise NotImplementedError()
 | 
			
		||||
 | 
			
		||||
    def get_file_version(self, config: dict) -> str:
 | 
			
		||||
        """
 | 
			
		||||
        :param config: The bumpversion config as a dict
 | 
			
		||||
        :return: The current version from the config file
 | 
			
		||||
        """
 | 
			
		||||
        bumpversion: Union[str, None] = config.get("bumpversion", None)
 | 
			
		||||
        version: Union[str, None] = (
 | 
			
		||||
            bumpversion.get("current_version", None) if bumpversion else None
 | 
			
		||||
        bump_version: Union[str, None] = config.get("bumpversion", None)
 | 
			
		||||
        version: str = (
 | 
			
		||||
            bump_version.get("current_version", "0.0.0") if bump_version else "0.0.0"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        if not bumpversion:
 | 
			
		||||
            config["bumpversion"] = {}
 | 
			
		||||
            version = "0.0.0"
 | 
			
		||||
 | 
			
		||||
        if not version:
 | 
			
		||||
            config["bumpversion"]["current_version"] = "0.0.0"
 | 
			
		||||
            version = "0.0.0"
 | 
			
		||||
 | 
			
		||||
        return version
 | 
			
		||||
 | 
			
		||||
    def get_version_type(
 | 
			
		||||
 | 
			
		||||
@ -26,12 +26,14 @@ class Git(SCM):
 | 
			
		||||
 | 
			
		||||
        super().__init__()
 | 
			
		||||
 | 
			
		||||
    def _run_command(self, *args: str) -> subprocess.CompletedProcess[str]:
 | 
			
		||||
    def _run_command(
 | 
			
		||||
        self, *args: str, throwExceptions: bool = True
 | 
			
		||||
    ) -> subprocess.CompletedProcess[str]:
 | 
			
		||||
        return subprocess.run(
 | 
			
		||||
            args,
 | 
			
		||||
            capture_output=True,
 | 
			
		||||
            text=True,
 | 
			
		||||
            check=True,
 | 
			
		||||
            check=throwExceptions,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def _setup_git_user(self) -> None:
 | 
			
		||||
@ -75,7 +77,7 @@ class Git(SCM):
 | 
			
		||||
            )
 | 
			
		||||
            tagged_versions = proc.stdout.rstrip().split("\n")
 | 
			
		||||
        except subprocess.CalledProcessError as e:
 | 
			
		||||
            raise RuntimeError(
 | 
			
		||||
            raise SemverException(
 | 
			
		||||
                f"Error getting latest tagged git version: {str(e.stderr).rstrip()}"
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
@ -122,16 +124,20 @@ class Git(SCM):
 | 
			
		||||
        Commit and push the versioning changes
 | 
			
		||||
        :param branch: The branch to push
 | 
			
		||||
        """
 | 
			
		||||
        proc = self._run_command(self.git_bin, "push", "origin", branch)
 | 
			
		||||
        proc = self._run_command(
 | 
			
		||||
            self.git_bin, "push", "origin", branch, throwExceptions=False
 | 
			
		||||
        )
 | 
			
		||||
        if proc.returncode != 0:
 | 
			
		||||
            raise SemverException(
 | 
			
		||||
                f"Error pushing versioning changes to {branch}: {proc.stderr}"
 | 
			
		||||
            )
 | 
			
		||||
        proc = self._run_command(self.git_bin, "push", "origin", "--tags")
 | 
			
		||||
        proc = self._run_command(
 | 
			
		||||
            self.git_bin, "push", "origin", "--tags", throwExceptions=False
 | 
			
		||||
        )
 | 
			
		||||
        if proc.returncode != 0:
 | 
			
		||||
            raise SemverException(
 | 
			
		||||
                f"Error pushing versioning changes to {branch}: {proc.stderr}"
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
    def tag_version(self, version: str) -> None:
 | 
			
		||||
        self._run_command(self.git_bin, "tag", version)
 | 
			
		||||
        self._run_command(self.git_bin, "tag", version)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								semver/scm/mock.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								semver/scm/mock.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
from typing import Union
 | 
			
		||||
 | 
			
		||||
from semver.scm import SCM
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MockSCM(SCM):
 | 
			
		||||
    def get_tag_version(self) -> str:
 | 
			
		||||
        return "1.0.0"
 | 
			
		||||
 | 
			
		||||
    def get_branch(self) -> str:
 | 
			
		||||
        return "main"
 | 
			
		||||
 | 
			
		||||
    def get_merge_branch(self) -> Union[str, None]:
 | 
			
		||||
        return "main"
 | 
			
		||||
 | 
			
		||||
    def commit_and_push(self, branch: str) -> None:
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def tag_version(self, version: str) -> None:
 | 
			
		||||
        pass
 | 
			
		||||
							
								
								
									
										0
									
								
								semver/scm/tests/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								semver/scm/tests/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										100
									
								
								semver/scm/tests/test_git.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								semver/scm/tests/test_git.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,100 @@
 | 
			
		||||
import unittest
 | 
			
		||||
from unittest import mock
 | 
			
		||||
import subprocess
 | 
			
		||||
 | 
			
		||||
from semver.version_type import VersionType
 | 
			
		||||
from semver.exceptions import SemverException
 | 
			
		||||
from semver.scm import SCM
 | 
			
		||||
from semver.scm.git import Git
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestMockSCM(unittest.TestCase):
 | 
			
		||||
    @mock.patch("subprocess.run")
 | 
			
		||||
    def setUp(self, mock_subprocess_run: mock.Mock):
 | 
			
		||||
        # Mock the subprocess.run function to avoid
 | 
			
		||||
        # running actual git commands
 | 
			
		||||
        mock_subprocess_run.return_value.returncode = 0
 | 
			
		||||
        mock_subprocess_run.return_value.stdout = ""
 | 
			
		||||
 | 
			
		||||
        self.scm = Git()
 | 
			
		||||
 | 
			
		||||
    def test_run_command(self):
 | 
			
		||||
        proc: subprocess.CompletedProcess[str] = self.scm._run_command("echo", "hello")
 | 
			
		||||
        self.assertEqual(proc.stdout, "hello\n")
 | 
			
		||||
 | 
			
		||||
    @mock.patch("toml.load")
 | 
			
		||||
    @mock.patch("subprocess.run")
 | 
			
		||||
    def test_get_tag_version(
 | 
			
		||||
        self, mock_subprocess_run: mock.Mock, mock_toml_load: mock.Mock
 | 
			
		||||
    ):
 | 
			
		||||
        mock_toml_load.return_value = {"bumpversion": {"tag_name": "v{new_version}"}}
 | 
			
		||||
        mock_subprocess_run.return_value.stdout = "v1.0.0\n"
 | 
			
		||||
 | 
			
		||||
        expected_version = "v1.0.0"
 | 
			
		||||
        version = self.scm.get_tag_version()
 | 
			
		||||
        self.assertEqual(version, expected_version)
 | 
			
		||||
 | 
			
		||||
    @mock.patch("toml.load")
 | 
			
		||||
    @mock.patch("subprocess.run")
 | 
			
		||||
    def test_get_tag_version_git_fail(
 | 
			
		||||
        self, mock_subprocess_run: mock.Mock, mock_toml_load: mock.Mock
 | 
			
		||||
    ):
 | 
			
		||||
        mock_toml_load.return_value = {"bumpversion": {"tag_name": "v{new_version}"}}
 | 
			
		||||
        mock_subprocess_run.return_value.returncode = 1
 | 
			
		||||
        mock_subprocess_run.side_effect = subprocess.CalledProcessError(
 | 
			
		||||
            1, "git", "git error"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        with self.assertRaises(SemverException):
 | 
			
		||||
            self.scm.get_tag_version()
 | 
			
		||||
 | 
			
		||||
    @mock.patch("subprocess.run")
 | 
			
		||||
    def test_get_branch(self, mock_subprocess_run: mock.Mock):
 | 
			
		||||
        mock_subprocess_run.return_value.stdout = "main\n"
 | 
			
		||||
 | 
			
		||||
        expected_branch = "main"
 | 
			
		||||
        branch = self.scm.get_branch()
 | 
			
		||||
        self.assertEqual(branch, expected_branch)
 | 
			
		||||
 | 
			
		||||
    @mock.patch("subprocess.run")
 | 
			
		||||
    def test_get_merge_branch(self, mock_subprocess_run: mock.Mock):
 | 
			
		||||
        mock_subprocess_run.return_value.stdout = (
 | 
			
		||||
            "Merge pull request #1 from RightBrain-Networks/feature/example\n"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        expected_merge_branch = "feature/example"
 | 
			
		||||
        merge_branch = self.scm.get_merge_branch()
 | 
			
		||||
        self.assertEqual(merge_branch, expected_merge_branch)
 | 
			
		||||
 | 
			
		||||
    @mock.patch("subprocess.run")
 | 
			
		||||
    def test_commit_and_push(self, mock_subprocess_run: mock.Mock):
 | 
			
		||||
        mock_subprocess_run.return_value.returncode = 0
 | 
			
		||||
 | 
			
		||||
        branch = "main"
 | 
			
		||||
        self.scm.commit_and_push(branch)
 | 
			
		||||
 | 
			
		||||
    @mock.patch("subprocess.run")
 | 
			
		||||
    def test_commit_and_push_git_fail(self, mock_subprocess_run: mock.Mock):
 | 
			
		||||
        mock_subprocess_run.return_value.returncode = 1
 | 
			
		||||
 | 
			
		||||
        branch = "main"
 | 
			
		||||
        with self.assertRaises(SemverException):
 | 
			
		||||
            self.scm.commit_and_push(branch)
 | 
			
		||||
 | 
			
		||||
    @mock.patch("subprocess.run")
 | 
			
		||||
    def test_commit_and_push_git_fail_tags(self, mock_subprocess_run: mock.Mock):
 | 
			
		||||
        mock_subprocess_run.side_effect = [
 | 
			
		||||
            mock.Mock(returncode=0),
 | 
			
		||||
            mock.Mock(returncode=1),
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
        branch = "main"
 | 
			
		||||
        with self.assertRaises(SemverException):
 | 
			
		||||
            self.scm.commit_and_push(branch)
 | 
			
		||||
 | 
			
		||||
    @mock.patch("subprocess.run")
 | 
			
		||||
    def test_tag_version(self, mock_subprocess_run: mock.Mock):
 | 
			
		||||
        mock_subprocess_run.return_value.returncode = 0
 | 
			
		||||
 | 
			
		||||
        version = "1.0.0"
 | 
			
		||||
        self.scm.tag_version(version)
 | 
			
		||||
							
								
								
									
										34
									
								
								semver/scm/tests/test_mock.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								semver/scm/tests/test_mock.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
			
		||||
import unittest
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
from semver.version_type import VersionType
 | 
			
		||||
from semver.scm import SCM
 | 
			
		||||
from semver.scm.mock import MockSCM
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestMockSCM(unittest.TestCase):
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        self.scm: SCM = MockSCM()
 | 
			
		||||
 | 
			
		||||
    def test_get_tag_version(self):
 | 
			
		||||
        expected_version = "1.0.0"
 | 
			
		||||
        version = self.scm.get_tag_version()
 | 
			
		||||
        self.assertEqual(version, expected_version)
 | 
			
		||||
 | 
			
		||||
    def test_get_branch(self):
 | 
			
		||||
        expected_branch = "main"
 | 
			
		||||
        branch = self.scm.get_branch()
 | 
			
		||||
        self.assertEqual(branch, expected_branch)
 | 
			
		||||
 | 
			
		||||
    def test_get_merge_branch(self):
 | 
			
		||||
        expected_merge_branch = "main"
 | 
			
		||||
        merge_branch = self.scm.get_merge_branch()
 | 
			
		||||
        self.assertEqual(merge_branch, expected_merge_branch)
 | 
			
		||||
 | 
			
		||||
    def test_commit_and_push(self):
 | 
			
		||||
        branch = "main"
 | 
			
		||||
        self.scm.commit_and_push(branch)
 | 
			
		||||
 | 
			
		||||
    def test_tag_version(self):
 | 
			
		||||
        version = "1.0.0"
 | 
			
		||||
        self.scm.tag_version(version)
 | 
			
		||||
							
								
								
									
										72
									
								
								semver/scm/tests/test_scm.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								semver/scm/tests/test_scm.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,72 @@
 | 
			
		||||
import unittest
 | 
			
		||||
 | 
			
		||||
from semver.version_type import VersionType
 | 
			
		||||
from semver.scm import SCM
 | 
			
		||||
from semver.scm.mock import MockSCM
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestSCM(unittest.TestCase):
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        self.scm: SCM = MockSCM()
 | 
			
		||||
 | 
			
		||||
    def test_get_file_version_existing_config(self):
 | 
			
		||||
        config = {"bumpversion": {"current_version": "1.2.3"}}
 | 
			
		||||
        expected_version = "1.2.3"
 | 
			
		||||
        version = self.scm.get_file_version(config)
 | 
			
		||||
        self.assertEqual(version, expected_version)
 | 
			
		||||
 | 
			
		||||
    def test_get_file_version_no_config(self):
 | 
			
		||||
        config = {}
 | 
			
		||||
        expected_version = "0.0.0"
 | 
			
		||||
        version = self.scm.get_file_version(config)
 | 
			
		||||
        self.assertEqual(version, expected_version)
 | 
			
		||||
 | 
			
		||||
    def test_get_file_version_no_version(self):
 | 
			
		||||
        config = {"bumpversion": {}}
 | 
			
		||||
        expected_version = "0.0.0"
 | 
			
		||||
        version = self.scm.get_file_version(config)
 | 
			
		||||
        self.assertEqual(version, expected_version)
 | 
			
		||||
 | 
			
		||||
    def test_get_version_type_major(self):
 | 
			
		||||
        merged_branch = "main"
 | 
			
		||||
        major_branches = ["main"]
 | 
			
		||||
        minor_branches = ["develop"]
 | 
			
		||||
        patch_branches = ["hotfix"]
 | 
			
		||||
        expected_version_type = VersionType.MAJOR
 | 
			
		||||
        version_type = self.scm.get_version_type(
 | 
			
		||||
            merged_branch, major_branches, minor_branches, patch_branches
 | 
			
		||||
        )
 | 
			
		||||
        self.assertEqual(version_type, expected_version_type)
 | 
			
		||||
 | 
			
		||||
    def test_get_version_type_minor(self):
 | 
			
		||||
        merged_branch = "develop"
 | 
			
		||||
        major_branches = ["main"]
 | 
			
		||||
        minor_branches = ["develop"]
 | 
			
		||||
        patch_branches = ["hotfix"]
 | 
			
		||||
        expected_version_type = VersionType.MINOR
 | 
			
		||||
        version_type = self.scm.get_version_type(
 | 
			
		||||
            merged_branch, major_branches, minor_branches, patch_branches
 | 
			
		||||
        )
 | 
			
		||||
        self.assertEqual(version_type, expected_version_type)
 | 
			
		||||
 | 
			
		||||
    def test_get_version_type_patch(self):
 | 
			
		||||
        merged_branch = "hotfix"
 | 
			
		||||
        major_branches = ["main"]
 | 
			
		||||
        minor_branches = ["develop"]
 | 
			
		||||
        patch_branches = ["hotfix"]
 | 
			
		||||
        expected_version_type = VersionType.PATCH
 | 
			
		||||
        version_type = self.scm.get_version_type(
 | 
			
		||||
            merged_branch, major_branches, minor_branches, patch_branches
 | 
			
		||||
        )
 | 
			
		||||
        self.assertEqual(version_type, expected_version_type)
 | 
			
		||||
 | 
			
		||||
    def test_get_version_type_none(self):
 | 
			
		||||
        merged_branch = "feature"
 | 
			
		||||
        major_branches = ["main"]
 | 
			
		||||
        minor_branches = ["develop"]
 | 
			
		||||
        patch_branches = ["hotfix"]
 | 
			
		||||
        expected_version_type = None
 | 
			
		||||
        version_type = self.scm.get_version_type(
 | 
			
		||||
            merged_branch, major_branches, minor_branches, patch_branches
 | 
			
		||||
        )
 | 
			
		||||
        self.assertEqual(version_type, expected_version_type)
 | 
			
		||||
		Reference in New Issue
	
	Block a user