From 7897491a8541daca1bd88449eb871a53c5cfbaba Mon Sep 17 00:00:00 2001 From: LeeW Date: Tue, 19 Nov 2019 12:55:48 -0500 Subject: [PATCH 01/11] refactor(git): Change get_commits into returning commits instead of lines of messsages #53 --- commitizen/bump.py | 25 +++++++++++++------------ commitizen/git.py | 9 ++++++--- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index 64ae2e469e..f95b1ed75c 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -17,7 +17,7 @@ def find_increment( - messages: List[str], regex: str = bump_pattern, increments_map: dict = bump_map + commits: List[str], regex: str = bump_pattern, increments_map: dict = bump_map ) -> Optional[str]: # Most important cases are major and minor. @@ -26,18 +26,19 @@ def find_increment( pattern = re.compile(regex) increment = None - for message in messages: - result = pattern.search(message) - if not result: - continue - found_keyword = result.group(0) - new_increment = increments_map_default[found_keyword] - if new_increment == "MAJOR": + for commit in commits: + for message in commit.split("\n"): + result = pattern.search(message) + if not result: + continue + found_keyword = result.group(0) + new_increment = increments_map_default[found_keyword] + if new_increment == "MAJOR": + increment = new_increment + break + elif increment == "MINOR" and new_increment == "PATCH": + continue increment = new_increment - break - elif increment == "MINOR" and new_increment == "PATCH": - continue - increment = new_increment return increment diff --git a/commitizen/git.py b/commitizen/git.py index 9f831e5b54..908daa0e11 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -21,15 +21,18 @@ def commit(message: str, args=""): def get_commits(start: str, end: str = "HEAD", from_beginning: bool = False) -> list: + delimiter = '"----------commit-delimiter----------"' + log_format = "%s%n%b" + git_log_cmd = f"git log --pretty={log_format}{delimiter}" - c = cmd.run(f"git log --pretty=format:%s%n%b {start}...{end}") + c = cmd.run(f"{git_log_cmd} {start}...{end}") if from_beginning: - c = cmd.run(f"git log --pretty=format:%s%n%b {end}") + c = cmd.run(f"{git_log_cmd} {end}") if not c.out: return [] - return c.out.split("\n") + return [commit.strip() for commit in c.out.split(delimiter) if commit] def tag_exist(tag: str) -> bool: From 6ed286875d7bf1c8bbad12f9e249b4969ef86199 Mon Sep 17 00:00:00 2001 From: LeeW Date: Tue, 19 Nov 2019 14:16:51 -0500 Subject: [PATCH 02/11] refactor(git): make arguments other then start and end in get_commit keyword arguments --- commitizen/git.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/commitizen/git.py b/commitizen/git.py index 908daa0e11..62bf7f129a 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -20,9 +20,14 @@ def commit(message: str, args=""): return c -def get_commits(start: str, end: str = "HEAD", from_beginning: bool = False) -> list: +def get_commits( + start: str, + end: str = "HEAD", + *, + from_beginning: bool = False, + log_format: str = "%s%n%b", +) -> list: delimiter = '"----------commit-delimiter----------"' - log_format = "%s%n%b" git_log_cmd = f"git log --pretty={log_format}{delimiter}" c = cmd.run(f"{git_log_cmd} {start}...{end}") @@ -32,7 +37,7 @@ def get_commits(start: str, end: str = "HEAD", from_beginning: bool = False) -> if not c.out: return [] - return [commit.strip() for commit in c.out.split(delimiter) if commit] + return [commit.strip() for commit in c.out.split(delimiter) if commit.strip()] def tag_exist(tag: str) -> bool: From bd6adfcb0b72a71194312bb10aba6033e759cd53 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Wed, 15 Jan 2020 19:32:54 +0800 Subject: [PATCH 03/11] feat(git): get_commits default from first_commit #53 --- commitizen/git.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/commitizen/git.py b/commitizen/git.py index 62bf7f129a..a49e865ea7 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -20,13 +20,24 @@ def commit(message: str, args=""): return c +def get_first_commit() -> str: + c = cmd.run("git rev-list --max-parents=0 HEAD") + return c.out.strip() + + def get_commits( - start: str, + start: Optional[str] = None, end: str = "HEAD", *, from_beginning: bool = False, log_format: str = "%s%n%b", ) -> list: + """ + Get the commits betweeen start and end (incldue end but not start) + """ + if not start: + start = get_first_commit() + delimiter = '"----------commit-delimiter----------"' git_log_cmd = f"git log --pretty={log_format}{delimiter}" From efc1bdb6135e929f0b171f1dc81ca4f12fab993a Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 17 Jan 2020 11:44:44 +0800 Subject: [PATCH 04/11] refactor(git): Use GitCommit, GitTag object to store commit and git information --- commitizen/bump.py | 5 +- commitizen/commands/bump.py | 9 ++- commitizen/git.py | 100 +++++++++++++++++++++++------- tests/test_bump_find_increment.py | 22 ++++--- 4 files changed, 100 insertions(+), 36 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index f95b1ed75c..bfda1c4541 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -6,6 +6,7 @@ from packaging.version import Version +from commitizen.git import GitCommit from commitizen.defaults import ( MAJOR, MINOR, @@ -17,7 +18,7 @@ def find_increment( - commits: List[str], regex: str = bump_pattern, increments_map: dict = bump_map + commits: List[GitCommit], regex: str = bump_pattern, increments_map: dict = bump_map ) -> Optional[str]: # Most important cases are major and minor. @@ -27,7 +28,7 @@ def find_increment( increment = None for commit in commits: - for message in commit.split("\n"): + for message in commit.message.split("\n"): result = pattern.search(message) if not result: continue diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index aa658cbebc..1120840793 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, List import questionary from packaging.version import Version @@ -54,7 +54,7 @@ def is_initial_tag(self, current_tag_version: str, is_yes: bool = False) -> bool is_initial = questionary.confirm("Is this the first tag created?").ask() return is_initial - def find_increment(self, commits: list) -> Optional[str]: + def find_increment(self, commits: List[git.GitCommit]) -> Optional[str]: bump_pattern = self.cz.bump_pattern bump_map = self.cz.bump_map if not bump_map or not bump_pattern: @@ -93,7 +93,10 @@ def __call__(self): is_files_only: Optional[bool] = self.arguments["files_only"] is_initial = self.is_initial_tag(current_tag_version, is_yes) - commits = git.get_commits(current_tag_version, from_beginning=is_initial) + if is_initial: + commits = git.get_commits() + else: + commits = git.get_commits(current_tag_version) # No commits, there is no need to create an empty tag. # Unless we previously had a prerelease. diff --git a/commitizen/git.py b/commitizen/git.py index a49e865ea7..f6a92facdd 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -6,6 +6,36 @@ from commitizen import cmd +class GitObject: + def __eq__(self, other): + if not isinstance(other, GitObject): + return False + return self.rev == other.rev + + +class GitCommit(GitObject): + def __init__(self, rev, title, body=""): + self.rev = rev + self.title = title + self.body = body + + @property + def message(self): + return f"{self.title}\n\n{self.body}" + + def __repr__(self): + return f"{self.title} ({self.rev})" + + +class GitTag(GitObject): + def __init__(self, name, rev): + self.name = name + self.rev = rev + + def __repr__(self): + return f"{self.name} ({self.rev})" + + def tag(tag: str): c = cmd.run(f"git tag {tag}") return c @@ -20,35 +50,39 @@ def commit(message: str, args=""): return c -def get_first_commit() -> str: - c = cmd.run("git rev-list --max-parents=0 HEAD") - return c.out.strip() - - def get_commits( start: Optional[str] = None, end: str = "HEAD", *, - from_beginning: bool = False, - log_format: str = "%s%n%b", -) -> list: + log_format: str = "%H%n%s%n%b", + delimiter: str = "----------commit-delimiter----------", +) -> List[GitCommit]: """ - Get the commits betweeen start and end (incldue end but not start) + Get the commits betweeen start and end """ - if not start: - start = get_first_commit() - - delimiter = '"----------commit-delimiter----------"' git_log_cmd = f"git log --pretty={log_format}{delimiter}" - c = cmd.run(f"{git_log_cmd} {start}...{end}") - - if from_beginning: + if start: + c = cmd.run(f"{git_log_cmd} {start}...{end}") + else: c = cmd.run(f"{git_log_cmd} {end}") if not c.out: return [] - return [commit.strip() for commit in c.out.split(delimiter) if commit.strip()] + + git_commits = [] + for rev_and_commit in c.out.split(delimiter): + rev_and_commit = rev_and_commit.strip() + if not rev_and_commit: + continue + rev, title, *body_list = rev_and_commit.split("\n") + + if rev_and_commit: + git_commit = GitCommit( + rev=rev.strip(), title=title.strip(), body="\n".join(body_list).strip() + ) + git_commits.append(git_commit) + return git_commits def tag_exist(tag: str) -> bool: @@ -56,13 +90,6 @@ def tag_exist(tag: str) -> bool: return tag in c.out -def is_staging_clean() -> bool: - """Check if staing is clean""" - c = cmd.run("git diff --no-ext-diff --name-only") - c_cached = cmd.run("git diff --no-ext-diff --cached --name-only") - return not (bool(c.out) or bool(c_cached.out)) - - def get_latest_tag() -> Optional[str]: c = cmd.run("git describe --abbrev=0 --tags") if c.err: @@ -82,3 +109,28 @@ def find_git_project_root() -> Optional[Path]: if not c.err: return Path(c.out.strip()) return None + + +def get_tags_with_rev() -> List[GitTag]: + tag_delimiter = "---tag-delimiter---" + c = cmd.run( + ( + f"git tag --format='%(refname:lstrip=2){tag_delimiter}%(objectname)'" + " --sort=-committerdate" + ) + ) + if c.err or not c.out: + return [] + + git_tags = [] + for line in c.out.split("\n")[:-1]: + name, rev = line.split(tag_delimiter) + git_tags.append(GitTag(name.strip(), rev.strip())) + return git_tags + + +def is_staging_clean() -> bool: + """Check if staing is clean""" + c = cmd.run("git diff --no-ext-diff --name-only") + c_cached = cmd.run("git diff --no-ext-diff --cached --name-only") + return not (bool(c.out) or bool(c_cached.out)) diff --git a/tests/test_bump_find_increment.py b/tests/test_bump_find_increment.py index 160457c870..405410712a 100644 --- a/tests/test_bump_find_increment.py +++ b/tests/test_bump_find_increment.py @@ -3,6 +3,7 @@ SVE: Semantic version at the end """ from commitizen import bump +from commitizen.git import GitCommit NONE_INCREMENT_CC = ["docs(README): motivation", "ci: added travis"] @@ -45,49 +46,56 @@ def test_find_increment_type_patch(): messages = PATCH_INCREMENTS_CC - increment_type = bump.find_increment(messages) + commits = [GitCommit(rev="test", title=message) for message in messages] + increment_type = bump.find_increment(commits) assert increment_type == "PATCH" def test_find_increment_type_minor(): messages = MINOR_INCREMENTS_CC - increment_type = bump.find_increment(messages) + commits = [GitCommit(rev="test", title=message) for message in messages] + increment_type = bump.find_increment(commits) assert increment_type == "MINOR" def test_find_increment_type_major(): messages = MAJOR_INCREMENTS_CC - increment_type = bump.find_increment(messages) + commits = [GitCommit(rev="test", title=message) for message in messages] + increment_type = bump.find_increment(commits) assert increment_type == "MAJOR" def test_find_increment_type_patch_sve(): messages = PATCH_INCREMENTS_SVE + commits = [GitCommit(rev="test", title=message) for message in messages] increment_type = bump.find_increment( - messages, regex=semantic_version_pattern, increments_map=semantic_version_map + commits, regex=semantic_version_pattern, increments_map=semantic_version_map ) assert increment_type == "PATCH" def test_find_increment_type_minor_sve(): messages = MINOR_INCREMENTS_SVE + commits = [GitCommit(rev="test", title=message) for message in messages] increment_type = bump.find_increment( - messages, regex=semantic_version_pattern, increments_map=semantic_version_map + commits, regex=semantic_version_pattern, increments_map=semantic_version_map ) assert increment_type == "MINOR" def test_find_increment_type_major_sve(): messages = MAJOR_INCREMENTS_SVE + commits = [GitCommit(rev="test", title=message) for message in messages] increment_type = bump.find_increment( - messages, regex=semantic_version_pattern, increments_map=semantic_version_map + commits, regex=semantic_version_pattern, increments_map=semantic_version_map ) assert increment_type == "MAJOR" def test_find_increment_type_none(): messages = NONE_INCREMENT_CC + commits = [GitCommit(rev="test", title=message) for message in messages] increment_type = bump.find_increment( - messages, regex=semantic_version_pattern, increments_map=semantic_version_map + commits, regex=semantic_version_pattern, increments_map=semantic_version_map ) assert increment_type is None From b4f42f2169d916ac788702eb559a9458cd3d3f69 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 17 Jan 2020 11:46:18 +0800 Subject: [PATCH 05/11] refactor(cmd): reimplement how cmd is run In the original design, command to long will not be run. I use the code how invoke runs sunbprocess. https://github.com/pyinvoke/invoke/blob/master/invoke/runners.py#L1271 --- commitizen/cmd.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/commitizen/cmd.py b/commitizen/cmd.py index 17c81ed7af..67c7cf6bd0 100644 --- a/commitizen/cmd.py +++ b/commitizen/cmd.py @@ -10,9 +10,12 @@ class Command(NamedTuple): def run(cmd: str) -> Command: - cmd.split() process = subprocess.Popen( - cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE + cmd, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, ) stdout, stderr = process.communicate() return Command(stdout.decode(), stderr.decode(), stdout, stderr) From a85a48cdd133f3d9edaec6ae94a22e38f481d4b9 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Tue, 21 Jan 2020 10:18:33 +0800 Subject: [PATCH 06/11] test(all): fix test break due to cli block not a git project --- tests/commands/test_bump_command.py | 1 + tests/test_cli.py | 27 +++++++++++++++++++-------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index 48ebeebfeb..bd2537dcd9 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -106,6 +106,7 @@ def test_bump_is_not_specify(mocker, capsys, tmpdir): with pytest.raises(SystemExit): with tmpdir.as_cwd(): + cmd.run("git init") cli.main() expected_error_message = ( diff --git a/tests/test_cli.py b/tests/test_cli.py index 51638655b3..075b95eee3 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -2,10 +2,21 @@ import pytest -from commitizen import cli +from commitizen import cli, cmd from commitizen.__version__ import __version__ +@pytest.fixture(scope="function") +def tmp_git_project(tmpdir): + with tmpdir.as_cwd(): + with open("pyproject.toml", "w") as f: + f.write("[tool.commitizen]\n" 'version="0.1.0"') + + cmd.run("git init") + + yield + + def test_sysexit_no_argv(mocker, capsys): testargs = ["cz"] mocker.patch.object(sys, "argv", testargs) @@ -35,14 +46,14 @@ def test_name(mocker, capsys): assert out.startswith("JRA") -def test_name_default_value(tmpdir, mocker, capsys): - with tmpdir.as_cwd() as _: - testargs = ["cz", "example"] - mocker.patch.object(sys, "argv", testargs) +@pytest.mark.usefixtures("tmp_git_project") +def test_name_default_value(mocker, capsys): + testargs = ["cz", "example"] + mocker.patch.object(sys, "argv", testargs) - cli.main() - out, _ = capsys.readouterr() - assert out.startswith("fix: correct minor typos in code") + cli.main() + out, _ = capsys.readouterr() + assert out.startswith("fix: correct minor typos in code") def test_ls(mocker, capsys): From 2d1233709d7a38dcab3a584a0689e3c473ff0a7c Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Tue, 21 Jan 2020 10:23:30 +0800 Subject: [PATCH 07/11] test(tests/conftest): move tmp_git_project and tmp_commitizen_project into conftest they're commonly used fixture among all tests --- tests/commands/test_bump_command.py | 23 ++++++----------------- tests/conftest.py | 18 ++++++++++++++++++ tests/test_cli.py | 13 +------------ 3 files changed, 25 insertions(+), 29 deletions(-) create mode 100644 tests/conftest.py diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index bd2537dcd9..e5ef886f63 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -8,17 +8,6 @@ from commitizen import cli, cmd, git -@pytest.fixture(scope="function") -def tmp_git_project(tmpdir): - with tmpdir.as_cwd(): - with open("pyproject.toml", "w") as f: - f.write("[tool.commitizen]\n" 'version="0.1.0"') - - cmd.run("git init") - - yield - - def create_file_and_commit(message: str, filename: Optional[str] = None): if not filename: filename = str(uuid.uuid4()) @@ -28,7 +17,7 @@ def create_file_and_commit(message: str, filename: Optional[str] = None): git.commit(message) -@pytest.mark.usefixtures("tmp_git_project") +@pytest.mark.usefixtures("tmp_commitizen_project") def test_bump_command(mocker): # MINOR create_file_and_commit("feat: new file") @@ -101,13 +90,12 @@ def test_bump_when_bumpping_is_not_support(mocker, capsys, tmpdir): assert "'cz_jira' rule does not support bump" in err -def test_bump_is_not_specify(mocker, capsys, tmpdir): +@pytest.mark.usefixtures("tmp_git_project") +def test_bump_is_not_specify(mocker, capsys): mocker.patch.object(sys, "argv", ["cz", "bump"]) with pytest.raises(SystemExit): - with tmpdir.as_cwd(): - cmd.run("git init") - cli.main() + cli.main() expected_error_message = ( "[NO_VERSION_SPECIFIED]\n" @@ -119,7 +107,8 @@ def test_bump_is_not_specify(mocker, capsys, tmpdir): assert expected_error_message in err -def test_bump_when_not_new_commit(mocker, capsys, tmp_git_project): +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_bump_when_not_new_commit(mocker, capsys): testargs = ["cz", "bump", "--yes"] mocker.patch.object(sys, "argv", testargs) diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000000..5d1acdcdfd --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,18 @@ +import pytest + +from commitizen import cmd + + +@pytest.fixture(scope="function") +def tmp_git_project(tmpdir): + with tmpdir.as_cwd(): + cmd.run("git init") + + yield + + +@pytest.fixture(scope="function") +@pytest.mark.usefixtures("tmp_git_project") +def tmp_commitizen_project(tmp_git_project): + with open("pyproject.toml", "w") as f: + f.write("[tool.commitizen]\n" 'version="0.1.0"') diff --git a/tests/test_cli.py b/tests/test_cli.py index 075b95eee3..e136096f37 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -2,21 +2,10 @@ import pytest -from commitizen import cli, cmd +from commitizen import cli from commitizen.__version__ import __version__ -@pytest.fixture(scope="function") -def tmp_git_project(tmpdir): - with tmpdir.as_cwd(): - with open("pyproject.toml", "w") as f: - f.write("[tool.commitizen]\n" 'version="0.1.0"') - - cmd.run("git init") - - yield - - def test_sysexit_no_argv(mocker, capsys): testargs = ["cz"] mocker.patch.object(sys, "argv", testargs) From f43cd6a789d61fa150b1e1caa413bdc6e396d474 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Tue, 21 Jan 2020 18:34:11 +0800 Subject: [PATCH 08/11] test(git): add test case for git object --- tests/test_git.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/test_git.py diff --git a/tests/test_git.py b/tests/test_git.py new file mode 100644 index 0000000000..36bb498f20 --- /dev/null +++ b/tests/test_git.py @@ -0,0 +1,11 @@ +from commitizen import git + + +def test_git_object_eq(): + git_commit = git.GitCommit( + rev="sha1-code", title="this is title", body="this is body" + ) + git_tag = git.GitTag(rev="sha1-code", name="0.0.1", date="2020-01-21") + + assert git_commit == git_tag + assert git_commit != "sha1-code" From 9f93074e176382599b79dbdfb26da7441b92ad9c Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Tue, 21 Jan 2020 18:36:33 +0800 Subject: [PATCH 09/11] refactor(git): rename get tag function to distinguish return str and GitTag --- commitizen/commands/init.py | 8 +++--- commitizen/git.py | 50 ++++++++++++++++++------------------- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/commitizen/commands/init.py b/commitizen/commands/init.py index 7fc39cdd01..6a06abb560 100644 --- a/commitizen/commands/init.py +++ b/commitizen/commands/init.py @@ -5,7 +5,7 @@ from commitizen import factory, out from commitizen.cz import registry from commitizen.config import BaseConfig, TomlConfig, IniConfig -from commitizen.git import get_latest_tag, get_all_tags +from commitizen.git import get_latest_tag_name, get_tag_names from commitizen.defaults import config_files @@ -57,7 +57,7 @@ def _ask_name(self) -> str: return name def _ask_tag(self) -> str: - latest_tag = get_latest_tag() + latest_tag = get_latest_tag_name() if not latest_tag: out.error("No Existing Tag. Set tag to v0.0.1") return "0.0.1" @@ -66,14 +66,14 @@ def _ask_tag(self) -> str: f"Is {latest_tag} the latest tag?", style=self.cz.style, default=False ).ask() if not is_correct_tag: - tags = get_all_tags() + tags = get_tag_names() if not tags: out.error("No Existing Tag. Set tag to v0.0.1") return "0.0.1" latest_tag = questionary.select( "Please choose the latest tag: ", - choices=get_all_tags(), + choices=get_tag_names(), style=self.cz.style, ).ask() diff --git a/commitizen/git.py b/commitizen/git.py index f6a92facdd..0853d76005 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -15,9 +15,9 @@ def __eq__(self, other): class GitCommit(GitObject): def __init__(self, rev, title, body=""): - self.rev = rev - self.title = title - self.body = body + self.rev = rev.strip() + self.title = title.strip() + self.body = body.strip() @property def message(self): @@ -28,9 +28,10 @@ def __repr__(self): class GitTag(GitObject): - def __init__(self, name, rev): - self.name = name - self.rev = rev + def __init__(self, name, rev, date): + self.rev = rev.strip() + self.name = name.strip() + self.date = date.strip() def __repr__(self): return f"{self.name} ({self.rev})" @@ -85,19 +86,34 @@ def get_commits( return git_commits +def get_tags(dateformat: str = "%Y-%m-%d") -> List[GitTag]: + inner_delimiter = "---inner_delimiter---" + formatter = ( + f"'%(refname:lstrip=2){inner_delimiter}" + f"%(objectname){inner_delimiter}" + f"%(committerdate:format:{dateformat})'" + ) + c = cmd.run(f"git tag --format={formatter} --sort=-committerdate") + if c.err or not c.out: + return [] + + git_tags = [GitTag(*line.split(inner_delimiter)) for line in c.out.split("\n")[:-1]] + return git_tags + + def tag_exist(tag: str) -> bool: c = cmd.run(f"git tag --list {tag}") return tag in c.out -def get_latest_tag() -> Optional[str]: +def get_latest_tag_name() -> Optional[str]: c = cmd.run("git describe --abbrev=0 --tags") if c.err: return None return c.out.strip() -def get_all_tags() -> Optional[List[str]]: +def get_tag_names() -> Optional[List[str]]: c = cmd.run("git tag --list") if c.err: return [] @@ -111,24 +127,6 @@ def find_git_project_root() -> Optional[Path]: return None -def get_tags_with_rev() -> List[GitTag]: - tag_delimiter = "---tag-delimiter---" - c = cmd.run( - ( - f"git tag --format='%(refname:lstrip=2){tag_delimiter}%(objectname)'" - " --sort=-committerdate" - ) - ) - if c.err or not c.out: - return [] - - git_tags = [] - for line in c.out.split("\n")[:-1]: - name, rev = line.split(tag_delimiter) - git_tags.append(GitTag(name.strip(), rev.strip())) - return git_tags - - def is_staging_clean() -> bool: """Check if staing is clean""" c = cmd.run("git diff --no-ext-diff --name-only") From 85027f790c578213efd26a94404869ac58f18c06 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Tue, 21 Jan 2020 18:55:53 +0800 Subject: [PATCH 10/11] refactor(commands/bump): rename parameter into bump_setting to distinguish bump_setting and argument --- commitizen/commands/bump.py | 40 ++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 1120840793..605fde9878 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -20,17 +20,11 @@ class Bump: def __init__(self, config: BaseConfig, arguments: dict): self.config: BaseConfig = config self.arguments: dict = arguments - self.parameters: dict = { + self.bump_settings: dict = { **config.settings, **{ key: arguments[key] - for key in [ - "dry_run", - "tag_format", - "prerelease", - "increment", - "bump_message", - ] + for key in ["tag_format", "prerelease", "increment", "bump_message"] if arguments[key] is not None }, } @@ -65,10 +59,10 @@ def find_increment(self, commits: List[git.GitCommit]) -> Optional[str]: ) return increment - def __call__(self): + def __call__(self): # noqa: C901 """Steps executed to bump.""" try: - current_version_instance: Version = Version(self.parameters["version"]) + current_version_instance: Version = Version(self.bump_settings["version"]) except TypeError: out.error( "[NO_VERSION_SPECIFIED]\n" @@ -79,19 +73,21 @@ def __call__(self): # Initialize values from sources (conf) current_version: str = self.config.settings["version"] - tag_format: str = self.parameters["tag_format"] - bump_commit_message: str = self.parameters["bump_message"] - current_tag_version: str = bump.create_tag( - current_version, tag_format=tag_format - ) - version_files: list = self.parameters["version_files"] - dry_run: bool = self.parameters["dry_run"] + tag_format: str = self.bump_settings["tag_format"] + bump_commit_message: str = self.bump_settings["bump_message"] + version_files: list = self.bump_settings["version_files"] + + dry_run: bool = self.arguments["dry_run"] is_yes: bool = self.arguments["yes"] - prerelease: str = self.arguments["prerelease"] increment: Optional[str] = self.arguments["increment"] + prerelease: str = self.arguments["prerelease"] is_files_only: Optional[bool] = self.arguments["files_only"] + current_tag_version: str = bump.create_tag( + current_version, tag_format=tag_format + ) + is_initial = self.is_initial_tag(current_tag_version, is_yes) if is_initial: commits = git.get_commits() @@ -121,9 +117,11 @@ def __call__(self): ) # Report found information - out.write(message) - out.write(f"tag to create: {new_tag_version}") - out.write(f"increment detected: {increment}") + out.write( + f"message\n" + f"tag to create: {new_tag_version}\n" + f"increment detected: {increment}\n" + ) # Do not perform operations over files or git. if dry_run: From e24ff2d02932530eabe8a640c75a729505d3b958 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Tue, 21 Jan 2020 19:13:43 +0800 Subject: [PATCH 11/11] test(git): add test case for get tags functions --- tests/test_git.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/test_git.py b/tests/test_git.py index 36bb498f20..ef7cb2cdc9 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -1,6 +1,12 @@ from commitizen import git +class FakeCommand: + def __init__(self, out=None, err=None): + self.out = out + self.err = err + + def test_git_object_eq(): git_commit = git.GitCommit( rev="sha1-code", title="this is title", body="this is body" @@ -9,3 +15,35 @@ def test_git_object_eq(): assert git_commit == git_tag assert git_commit != "sha1-code" + + +def test_get_tags(mocker): + tag_str = ( + "v1.0.0---inner_delimiter---333---inner_delimiter---2020-01-20\n" + "v0.5.0---inner_delimiter---222---inner_delimiter---2020-01-17\n" + "v0.0.1---inner_delimiter---111---inner_delimiter---2020-01-17\n" + ) + mocker.patch("commitizen.cmd.run", return_value=FakeCommand(out=tag_str)) + + git_tags = git.get_tags() + latest_git_tag = git_tags[0] + assert latest_git_tag.rev == "333" + assert latest_git_tag.name == "v1.0.0" + assert latest_git_tag.date == "2020-01-20" + + mocker.patch( + "commitizen.cmd.run", return_value=FakeCommand(out="", err="No tag available") + ) + assert git.get_tags() == [] + + +def test_get_tag_names(mocker): + tag_str = "v1.0.0\n" "v0.5.0\n" "v0.0.1\n" + mocker.patch("commitizen.cmd.run", return_value=FakeCommand(out=tag_str)) + + assert git.get_tag_names() == ["v1.0.0", "v0.5.0", "v0.0.1"] + + mocker.patch( + "commitizen.cmd.run", return_value=FakeCommand(out="", err="No tag available") + ) + assert git.get_tag_names() == []