Rework get_version and various improvements
This commit is contained in:
parent
d1e2d77a29
commit
fa41212e77
@ -12,30 +12,17 @@ from semver.scm import SCM
|
||||
from semver.scm.git import Git
|
||||
|
||||
from semver.semver import SemVer
|
||||
from semver.utils import setting_to_array
|
||||
|
||||
from semver.exceptions import (
|
||||
NoMergeFoundException,
|
||||
NotMainBranchException,
|
||||
NoGitFlowException,
|
||||
SemverException,
|
||||
)
|
||||
|
||||
version = "0.0.0"
|
||||
|
||||
|
||||
def _setting_to_array(setting) -> List[str]:
|
||||
"""
|
||||
Get a setting from the config file and return it as a list
|
||||
:param setting: The setting to get from the config file
|
||||
:return: The setting as a list
|
||||
"""
|
||||
config: dict = toml.load("./.bumpversion.cfg")
|
||||
semver: dict = config.get("semver", {})
|
||||
value: str = semver.get(setting, "")
|
||||
|
||||
return [v.strip() for v in value.split(",") if v.strip()]
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point for the application"""
|
||||
parser = argparse.ArgumentParser(description="Bump Semantic Version.")
|
||||
@ -63,10 +50,10 @@ def main():
|
||||
|
||||
app = SemVer(
|
||||
scm=scm,
|
||||
main_branches=_setting_to_array("main_branches"),
|
||||
major_branches=_setting_to_array("major_branches"),
|
||||
minor_branches=_setting_to_array("minor_branches"),
|
||||
patch_branches=_setting_to_array("patch_branches"),
|
||||
main_branches=setting_to_array("main_branches"),
|
||||
major_branches=setting_to_array("major_branches"),
|
||||
minor_branches=setting_to_array("minor_branches"),
|
||||
patch_branches=setting_to_array("patch_branches"),
|
||||
)
|
||||
|
||||
if args.debug:
|
||||
|
@ -1,62 +1,57 @@
|
||||
import argparse
|
||||
import re
|
||||
import subprocess
|
||||
from semver.logger import logging, logger, console_logger
|
||||
from semver.utils import get_tag_version, get_file_version, DEVNULL
|
||||
|
||||
from semver.logger import logging, console_logger
|
||||
from semver import SemVer
|
||||
from semver.bump import bump_version
|
||||
|
||||
def get_version(build=0,version_format=None,dot=False):
|
||||
version = get_tag_version()
|
||||
|
||||
# Get the commit hash of the version
|
||||
v_hash = subprocess.Popen(['git', 'rev-list', '-n', '1', version], stdout=subprocess.PIPE,
|
||||
stderr=DEVNULL, cwd='.').stdout.read().decode('utf-8').rstrip()
|
||||
# Get the current commit hash
|
||||
c_hash = subprocess.Popen(['git', 'rev-parse', 'HEAD'], stdout=subprocess.PIPE,
|
||||
stderr=DEVNULL, cwd='.').stdout.read().decode('utf-8').rstrip()
|
||||
|
||||
# If the version commit hash and current commit hash
|
||||
# do not match return the branch name else return the version
|
||||
if v_hash != c_hash:
|
||||
logger.debug("v_hash and c_hash do not match!")
|
||||
branch = subprocess.Popen(['git', 'rev-parse', '--abbrev-ref', 'HEAD'], stdout=subprocess.PIPE,
|
||||
stderr=DEVNULL, cwd='.').stdout.read().decode('utf-8').rstrip()
|
||||
semver = SemVer()
|
||||
semver.merged_branch = branch
|
||||
logger.debug("merged branch is: {}".format(semver.merged_branch))
|
||||
version_type = semver.get_version_type()
|
||||
logger.debug("version type is: {}".format(version_type))
|
||||
if version_type:
|
||||
|
||||
next_version = bump_version(get_tag_version(), version_type, False, False)
|
||||
|
||||
if version_format in ('npm','docker'):
|
||||
return "{}-{}.{}".format(next_version,re.sub(r'[/_]', '-', branch),build)
|
||||
if version_format == 'maven':
|
||||
qualifier = 'SNAPSHOT' if build == 0 else build
|
||||
return "{}-{}-{}".format(next_version,re.sub(r'[/_]', '-', branch),qualifier)
|
||||
if dot:
|
||||
branch = branch.replace('/','.')
|
||||
return branch
|
||||
return version
|
||||
from semver.utils import setting_to_array
|
||||
from semver.scm.git import Git
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Get Version or Branch.')
|
||||
parser.add_argument('-d', '--dot', help='Switch out / for . to be used in docker tag', action='store_true', dest='dot')
|
||||
parser.add_argument('-D', '--debug', help='Sets logging level to DEBUG', action='store_true', dest='debug', default=False)
|
||||
parser.add_argument('-f', '--format', help='Format for pre-release version syntax', choices=['npm','maven','docker'], default=None)
|
||||
parser.add_argument('-b', '--build-number', help='Build number, used in pre-releases', default=0)
|
||||
|
||||
parser = argparse.ArgumentParser(description="Get Version or Branch.")
|
||||
parser.add_argument(
|
||||
"-d",
|
||||
"--dot",
|
||||
help="Switch out / for . to be used in docker tag",
|
||||
action="store_true",
|
||||
dest="dot",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-D",
|
||||
"--debug",
|
||||
help="Sets logging level to DEBUG",
|
||||
action="store_true",
|
||||
dest="debug",
|
||||
default=False,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-f",
|
||||
"--format",
|
||||
help="Format for pre-release version syntax",
|
||||
choices=["npm", "maven", "docker"],
|
||||
default=None,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-b", "--build-number", help="Build number, used in pre-releases", default=0
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.debug:
|
||||
console_logger.setLevel(logging.DEBUG)
|
||||
|
||||
print(get_version(args.build_number,args.format,args.dot))
|
||||
semver = SemVer(
|
||||
scm=Git(),
|
||||
main_branches=setting_to_array("main_branches"),
|
||||
major_branches=setting_to_array("major_branches"),
|
||||
minor_branches=setting_to_array("minor_branches"),
|
||||
patch_branches=setting_to_array("patch_branches"),
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
try: main()
|
||||
except: raise
|
||||
print(semver.get_version(args.build_number, args.format, args.dot))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
except Exception as e:
|
||||
raise e
|
||||
|
@ -26,6 +26,14 @@ class SCM(ABC):
|
||||
def tag_version(self, version: str) -> None:
|
||||
raise NotImplementedError()
|
||||
|
||||
@abstractmethod
|
||||
def get_version_hash(self, version: str) -> str:
|
||||
raise NotImplementedError()
|
||||
|
||||
@abstractmethod
|
||||
def get_hash(self) -> str:
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_file_version(self, config: dict) -> str:
|
||||
"""
|
||||
:param config: The bumpversion config as a dict
|
||||
|
@ -106,8 +106,6 @@ class Git(SCM):
|
||||
|
||||
branch: str = self.get_branch()
|
||||
|
||||
logger.info(f"Main branch is {branch}")
|
||||
|
||||
matches = self.git_commit_pattern.search(
|
||||
message.replace("\\n", "\n").replace("\\", "")
|
||||
)
|
||||
@ -140,4 +138,25 @@ class Git(SCM):
|
||||
)
|
||||
|
||||
def tag_version(self, version: str) -> None:
|
||||
"""
|
||||
Creates a git tag at HEAD with the given version
|
||||
:param version: The version to tag
|
||||
"""
|
||||
self._run_command(self.git_bin, "tag", version)
|
||||
|
||||
def get_version_hash(self, version: str) -> str:
|
||||
"""
|
||||
Get the hash of the commit that has the given version
|
||||
:param version: The version to get the hash for
|
||||
:return: The hash of the commit that has the given version
|
||||
"""
|
||||
proc = self._run_command(self.git_bin, "rev-list", "-n", "1", version)
|
||||
return proc.stdout.rstrip()
|
||||
|
||||
def get_hash(self) -> str:
|
||||
"""
|
||||
Get the hash of the current commit
|
||||
:return: The hash of the current commit
|
||||
"""
|
||||
proc = self._run_command(self.git_bin, "rev-parse", "HEAD")
|
||||
return proc.stdout.rstrip()
|
||||
|
@ -18,3 +18,9 @@ class MockSCM(SCM):
|
||||
|
||||
def tag_version(self, version: str) -> None:
|
||||
pass
|
||||
|
||||
def get_version_hash(self, version: str) -> str:
|
||||
return "HASH"
|
||||
|
||||
def get_hash(self) -> str:
|
||||
return "HASH"
|
||||
|
@ -98,3 +98,20 @@ class TestMockSCM(unittest.TestCase):
|
||||
|
||||
version = "1.0.0"
|
||||
self.scm.tag_version(version)
|
||||
|
||||
@mock.patch("subprocess.run")
|
||||
def test_get_version_hash(self, mock_subprocess_run: mock.Mock):
|
||||
mock_subprocess_run.return_value.stdout = "HASH\n"
|
||||
|
||||
version = "1.0.0"
|
||||
expected_hash = "HASH"
|
||||
version_hash = self.scm.get_version_hash(version)
|
||||
self.assertEqual(version_hash, expected_hash)
|
||||
|
||||
@mock.patch("subprocess.run")
|
||||
def test_get_hash(self, mock_subprocess_run: mock.Mock):
|
||||
mock_subprocess_run.return_value.stdout = "HASH\n"
|
||||
|
||||
expected_hash = "HASH"
|
||||
version_hash = self.scm.get_hash()
|
||||
self.assertEqual(version_hash, expected_hash)
|
||||
|
@ -32,3 +32,14 @@ class TestMockSCM(unittest.TestCase):
|
||||
def test_tag_version(self):
|
||||
version = "1.0.0"
|
||||
self.scm.tag_version(version)
|
||||
|
||||
def test_get_version_hash(self):
|
||||
version = "1.0.0"
|
||||
expected_hash = "HASH"
|
||||
version_hash = self.scm.get_version_hash(version)
|
||||
self.assertEqual(version_hash, expected_hash)
|
||||
|
||||
def test_get_hash(self):
|
||||
expected_hash = "HASH"
|
||||
version_hash = self.scm.get_hash()
|
||||
self.assertEqual(version_hash, expected_hash)
|
||||
|
@ -1,5 +1,6 @@
|
||||
from typing import List, Union
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
import toml
|
||||
|
||||
@ -139,6 +140,52 @@ class SemVer:
|
||||
f"Tried to version file: '{file_path}' but it doesn't exist!"
|
||||
)
|
||||
|
||||
def get_version(
|
||||
self, build: int = 0, version_format: Union[str, None] = None, dot: bool = False
|
||||
):
|
||||
"""
|
||||
Get the version of the repo
|
||||
:param build: The build number
|
||||
:param version_format: The format of the version
|
||||
:param dot: Whether or not to replace / with .
|
||||
:return: The version
|
||||
"""
|
||||
version = self._scm.get_tag_version()
|
||||
|
||||
# Get the commit hash of the version
|
||||
v_hash = self._scm.get_version_hash(version)
|
||||
# Get the current commit hash
|
||||
c_hash = self._scm.get_hash()
|
||||
|
||||
# If the version commit hash and current commit hash
|
||||
# do not match return the branch name else return the version
|
||||
if v_hash != c_hash:
|
||||
logger.debug("v_hash and c_hash do not match!")
|
||||
branch = self._scm.get_branch()
|
||||
logger.debug("merged branch is: {}".format(branch))
|
||||
version_type = self._scm.get_version_type(
|
||||
branch, self._major_branches, self._minor_branches, self._patch_branches
|
||||
)
|
||||
logger.debug("version type is: {}".format(version_type))
|
||||
if version_type:
|
||||
next_version = self._bump_version(
|
||||
self._scm.get_tag_version(), version_type, False, False
|
||||
)
|
||||
|
||||
if version_format in ("npm", "docker"):
|
||||
return "{}-{}.{}".format(
|
||||
next_version, re.sub(r"[/_]", "-", branch), build
|
||||
)
|
||||
if version_format == "maven":
|
||||
qualifier = "SNAPSHOT" if build == 0 else build
|
||||
return "{}-{}-{}".format(
|
||||
next_version, re.sub(r"[/_]", "-", branch), qualifier
|
||||
)
|
||||
if dot:
|
||||
branch = branch.replace("/", ".")
|
||||
return branch
|
||||
return version
|
||||
|
||||
def run(self, push=True):
|
||||
"""
|
||||
Run the versioning process
|
||||
@ -152,9 +199,9 @@ class SemVer:
|
||||
self._merged_branch = self._scm.get_merge_branch()
|
||||
|
||||
if not self._merged_branch:
|
||||
raise NoMergeFoundException()
|
||||
raise NoMergeFoundException("No merge found")
|
||||
if self._branch not in self._main_branches:
|
||||
raise NotMainBranchException()
|
||||
raise NotMainBranchException("Not a main branch")
|
||||
|
||||
self._version_type = self._scm.get_version_type(
|
||||
self._branch,
|
||||
@ -164,7 +211,7 @@ class SemVer:
|
||||
)
|
||||
|
||||
if not self._version_type:
|
||||
raise NoGitFlowException()
|
||||
raise NoGitFlowException("Could not determine version type")
|
||||
|
||||
self._version_repo()
|
||||
if push:
|
||||
|
@ -12,7 +12,7 @@ from semver.exceptions import (
|
||||
)
|
||||
|
||||
|
||||
class TestSCM(unittest.TestCase):
|
||||
class TestSemVer(unittest.TestCase):
|
||||
def setUp(self):
|
||||
scm = mock.MagicMock(MockSCM())
|
||||
self.semver: SemVer = SemVer(scm=scm)
|
||||
@ -142,3 +142,52 @@ class TestSCM(unittest.TestCase):
|
||||
|
||||
with self.assertRaises(NoGitFlowException):
|
||||
self.semver.run()
|
||||
|
||||
@mock.patch("semver.semver.SemVer._bump_version")
|
||||
def test_get_version(self, mock_bump_version: mock.Mock):
|
||||
self.semver._scm.get_branch.return_value = "feature/example"
|
||||
self.semver._scm.get_tag_version.return_value = "1.0.0"
|
||||
self.semver._scm.get_version_hash.return_value = "HASH"
|
||||
self.semver._scm.get_hash.return_value = "ALT_HASH"
|
||||
|
||||
mock_bump_version.return_value = "1.0.1"
|
||||
|
||||
expected_version = "1.0.0+HASH"
|
||||
version = self.semver.get_version(dot=True)
|
||||
self.assertEqual(version, "feature.example")
|
||||
|
||||
@mock.patch("semver.semver.SemVer._bump_version")
|
||||
def test_get_version_docker(self, mock_bump_version: mock.Mock):
|
||||
self.semver._scm.get_branch.return_value = "feature/example"
|
||||
self.semver._scm.get_tag_version.return_value = "1.0.0"
|
||||
self.semver._scm.get_version_hash.return_value = "HASH"
|
||||
self.semver._scm.get_hash.return_value = "ALT_HASH"
|
||||
|
||||
mock_bump_version.return_value = "1.0.1"
|
||||
|
||||
expected_version = "1.0.0+HASH"
|
||||
version = self.semver.get_version(version_format="docker")
|
||||
self.assertEqual(version, "1.0.1-feature-example.0")
|
||||
|
||||
@mock.patch("semver.semver.SemVer._bump_version")
|
||||
def test_get_version_maven(self, mock_bump_version: mock.Mock):
|
||||
self.semver._scm.get_branch.return_value = "feature/example"
|
||||
self.semver._scm.get_tag_version.return_value = "1.0.0"
|
||||
self.semver._scm.get_version_hash.return_value = "HASH"
|
||||
self.semver._scm.get_hash.return_value = "ALT_HASH"
|
||||
|
||||
mock_bump_version.return_value = "1.0.1"
|
||||
|
||||
expected_version = "1.0.1-feature-example-SNAPSHOT"
|
||||
version = self.semver.get_version(version_format="maven")
|
||||
self.assertEqual(version, expected_version)
|
||||
|
||||
def test_get_version_no_hash(self):
|
||||
self.semver._scm.get_branch.return_value = "main"
|
||||
self.semver._scm.get_tag_version.return_value = "1.0.0"
|
||||
self.semver._scm.get_version_hash.return_value = "HASH"
|
||||
self.semver._scm.get_hash.return_value = "HASH"
|
||||
|
||||
expected_version = "1.0.0"
|
||||
version = self.semver.get_version()
|
||||
self.assertEqual(version, expected_version)
|
||||
|
59
semver/tests/test_utils.py
Normal file
59
semver/tests/test_utils.py
Normal file
@ -0,0 +1,59 @@
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
from semver.utils import get_settings, setting_to_array
|
||||
from semver.exceptions import SemverException
|
||||
|
||||
|
||||
class TestUtils(unittest.TestCase):
|
||||
@mock.patch("toml.load")
|
||||
@mock.patch("pathlib.Path.is_file")
|
||||
def test_get_settings_toml(self, mock_is_file: mock.Mock, mock_toml: mock.Mock):
|
||||
get_settings.cache_clear()
|
||||
|
||||
mock_is_file.side_effect = [True, False]
|
||||
|
||||
mock_toml.return_value = {"1": {"a": "alpha", "fruit": "apple"}}
|
||||
settings = get_settings()
|
||||
self.assertEqual(settings, {"1": {"a": "alpha", "fruit": "apple"}})
|
||||
|
||||
@mock.patch("configparser.ConfigParser")
|
||||
@mock.patch("pathlib.Path.is_file")
|
||||
def test_get_settings_cfg(
|
||||
self, mock_is_file: mock.Mock, mock_config_parser: mock.Mock
|
||||
):
|
||||
get_settings.cache_clear()
|
||||
|
||||
mock_is_file.side_effect = [False, True]
|
||||
|
||||
mock_config_parser.return_value.read.return_value = ["./.bumpversion.cfg"]
|
||||
mock_config_parser.return_value.sections.return_value = ["1", "2", "3"]
|
||||
mock_config_parser.return_value.items.side_effect = [
|
||||
[("a", "alpha"), ("fruit", "apple")],
|
||||
[("b", "bravo"), ("fruit", "banana")],
|
||||
[("c", "charlie"), ("fruit", "cherry")],
|
||||
]
|
||||
|
||||
settings = get_settings()
|
||||
self.assertEqual(
|
||||
settings,
|
||||
{
|
||||
"1": {"a": "alpha", "fruit": "apple"},
|
||||
"2": {"b": "bravo", "fruit": "banana"},
|
||||
"3": {"c": "charlie", "fruit": "cherry"},
|
||||
},
|
||||
)
|
||||
|
||||
@mock.patch("pathlib.Path.is_file")
|
||||
def test_get_settings_no_file(self, mock_is_file: mock.Mock):
|
||||
get_settings.cache_clear()
|
||||
|
||||
mock_is_file.side_effect = [False, False]
|
||||
with self.assertRaises(SemverException):
|
||||
get_settings()
|
||||
|
||||
@mock.patch("semver.utils.get_settings")
|
||||
def test_setting_to_array(self, mock_get_settings: mock.Mock):
|
||||
mock_get_settings.return_value = {"semver": {"test": "test1, test2"}}
|
||||
settings = setting_to_array("test")
|
||||
self.assertEqual(settings, ["test1", "test2"])
|
38
semver/utils.py
Normal file
38
semver/utils.py
Normal file
@ -0,0 +1,38 @@
|
||||
from typing import List
|
||||
from pathlib import Path
|
||||
from functools import cache
|
||||
import configparser
|
||||
|
||||
import toml
|
||||
|
||||
from semver.exceptions import SemverException
|
||||
|
||||
|
||||
@cache
|
||||
def get_settings() -> dict:
|
||||
"""
|
||||
Get the settings from the config file
|
||||
:return: The settings from the config file
|
||||
"""
|
||||
if Path("./.bumpversion.toml").is_file():
|
||||
return toml.load("./.bumpversion.toml")
|
||||
if Path("./.bumpversion.cfg").is_file():
|
||||
config = configparser.ConfigParser()
|
||||
config.read("./.bumpversion.cfg")
|
||||
|
||||
return {section: dict(config.items(section)) for section in config.sections()}
|
||||
|
||||
raise SemverException("No config file found")
|
||||
|
||||
|
||||
def setting_to_array(setting) -> List[str]:
|
||||
"""
|
||||
Get a setting from the config file and return it as a list
|
||||
:param setting: The setting to get from the config file
|
||||
:return: The setting as a list
|
||||
"""
|
||||
config: dict = get_settings()
|
||||
semver: dict = config.get("semver", {})
|
||||
value: str = semver.get(setting, "")
|
||||
|
||||
return [v.strip() for v in value.split(",") if v.strip()]
|
Loading…
Reference in New Issue
Block a user