Skip to content

Commit cbc145e

Browse files
authored
Merge pull request #125 from Lee-W/refactor
Refactor
2 parents cd1d4ea + e24ff2d commit cbc145e

File tree

10 files changed

+227
-87
lines changed

10 files changed

+227
-87
lines changed

commitizen/bump.py

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from packaging.version import Version
88

9+
from commitizen.git import GitCommit
910
from commitizen.defaults import (
1011
MAJOR,
1112
MINOR,
@@ -17,7 +18,7 @@
1718

1819

1920
def find_increment(
20-
messages: List[str], regex: str = bump_pattern, increments_map: dict = bump_map
21+
commits: List[GitCommit], regex: str = bump_pattern, increments_map: dict = bump_map
2122
) -> Optional[str]:
2223

2324
# Most important cases are major and minor.
@@ -26,18 +27,19 @@ def find_increment(
2627
pattern = re.compile(regex)
2728
increment = None
2829

29-
for message in messages:
30-
result = pattern.search(message)
31-
if not result:
32-
continue
33-
found_keyword = result.group(0)
34-
new_increment = increments_map_default[found_keyword]
35-
if new_increment == "MAJOR":
30+
for commit in commits:
31+
for message in commit.message.split("\n"):
32+
result = pattern.search(message)
33+
if not result:
34+
continue
35+
found_keyword = result.group(0)
36+
new_increment = increments_map_default[found_keyword]
37+
if new_increment == "MAJOR":
38+
increment = new_increment
39+
break
40+
elif increment == "MINOR" and new_increment == "PATCH":
41+
continue
3642
increment = new_increment
37-
break
38-
elif increment == "MINOR" and new_increment == "PATCH":
39-
continue
40-
increment = new_increment
4143

4244
return increment
4345

commitizen/cmd.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@ class Command(NamedTuple):
1010

1111

1212
def run(cmd: str) -> Command:
13-
cmd.split()
1413
process = subprocess.Popen(
15-
cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE
14+
cmd,
15+
shell=True,
16+
stdout=subprocess.PIPE,
17+
stderr=subprocess.PIPE,
18+
stdin=subprocess.PIPE,
1619
)
1720
stdout, stderr = process.communicate()
1821
return Command(stdout.decode(), stderr.decode(), stdout, stderr)

commitizen/commands/bump.py

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Optional
1+
from typing import Optional, List
22

33
import questionary
44
from packaging.version import Version
@@ -20,17 +20,11 @@ class Bump:
2020
def __init__(self, config: BaseConfig, arguments: dict):
2121
self.config: BaseConfig = config
2222
self.arguments: dict = arguments
23-
self.parameters: dict = {
23+
self.bump_settings: dict = {
2424
**config.settings,
2525
**{
2626
key: arguments[key]
27-
for key in [
28-
"dry_run",
29-
"tag_format",
30-
"prerelease",
31-
"increment",
32-
"bump_message",
33-
]
27+
for key in ["tag_format", "prerelease", "increment", "bump_message"]
3428
if arguments[key] is not None
3529
},
3630
}
@@ -54,7 +48,7 @@ def is_initial_tag(self, current_tag_version: str, is_yes: bool = False) -> bool
5448
is_initial = questionary.confirm("Is this the first tag created?").ask()
5549
return is_initial
5650

57-
def find_increment(self, commits: list) -> Optional[str]:
51+
def find_increment(self, commits: List[git.GitCommit]) -> Optional[str]:
5852
bump_pattern = self.cz.bump_pattern
5953
bump_map = self.cz.bump_map
6054
if not bump_map or not bump_pattern:
@@ -65,10 +59,10 @@ def find_increment(self, commits: list) -> Optional[str]:
6559
)
6660
return increment
6761

68-
def __call__(self):
62+
def __call__(self): # noqa: C901
6963
"""Steps executed to bump."""
7064
try:
71-
current_version_instance: Version = Version(self.parameters["version"])
65+
current_version_instance: Version = Version(self.bump_settings["version"])
7266
except TypeError:
7367
out.error(
7468
"[NO_VERSION_SPECIFIED]\n"
@@ -79,21 +73,26 @@ def __call__(self):
7973

8074
# Initialize values from sources (conf)
8175
current_version: str = self.config.settings["version"]
82-
tag_format: str = self.parameters["tag_format"]
83-
bump_commit_message: str = self.parameters["bump_message"]
84-
current_tag_version: str = bump.create_tag(
85-
current_version, tag_format=tag_format
86-
)
87-
version_files: list = self.parameters["version_files"]
88-
dry_run: bool = self.parameters["dry_run"]
8976

77+
tag_format: str = self.bump_settings["tag_format"]
78+
bump_commit_message: str = self.bump_settings["bump_message"]
79+
version_files: list = self.bump_settings["version_files"]
80+
81+
dry_run: bool = self.arguments["dry_run"]
9082
is_yes: bool = self.arguments["yes"]
91-
prerelease: str = self.arguments["prerelease"]
9283
increment: Optional[str] = self.arguments["increment"]
84+
prerelease: str = self.arguments["prerelease"]
9385
is_files_only: Optional[bool] = self.arguments["files_only"]
9486

87+
current_tag_version: str = bump.create_tag(
88+
current_version, tag_format=tag_format
89+
)
90+
9591
is_initial = self.is_initial_tag(current_tag_version, is_yes)
96-
commits = git.get_commits(current_tag_version, from_beginning=is_initial)
92+
if is_initial:
93+
commits = git.get_commits()
94+
else:
95+
commits = git.get_commits(current_tag_version)
9796

9897
# No commits, there is no need to create an empty tag.
9998
# Unless we previously had a prerelease.
@@ -118,9 +117,11 @@ def __call__(self):
118117
)
119118

120119
# Report found information
121-
out.write(message)
122-
out.write(f"tag to create: {new_tag_version}")
123-
out.write(f"increment detected: {increment}")
120+
out.write(
121+
f"message\n"
122+
f"tag to create: {new_tag_version}\n"
123+
f"increment detected: {increment}\n"
124+
)
124125

125126
# Do not perform operations over files or git.
126127
if dry_run:

commitizen/commands/init.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from commitizen import factory, out
66
from commitizen.cz import registry
77
from commitizen.config import BaseConfig, TomlConfig, IniConfig
8-
from commitizen.git import get_latest_tag, get_all_tags
8+
from commitizen.git import get_latest_tag_name, get_tag_names
99
from commitizen.defaults import config_files
1010

1111

@@ -57,7 +57,7 @@ def _ask_name(self) -> str:
5757
return name
5858

5959
def _ask_tag(self) -> str:
60-
latest_tag = get_latest_tag()
60+
latest_tag = get_latest_tag_name()
6161
if not latest_tag:
6262
out.error("No Existing Tag. Set tag to v0.0.1")
6363
return "0.0.1"
@@ -66,14 +66,14 @@ def _ask_tag(self) -> str:
6666
f"Is {latest_tag} the latest tag?", style=self.cz.style, default=False
6767
).ask()
6868
if not is_correct_tag:
69-
tags = get_all_tags()
69+
tags = get_tag_names()
7070
if not tags:
7171
out.error("No Existing Tag. Set tag to v0.0.1")
7272
return "0.0.1"
7373

7474
latest_tag = questionary.select(
7575
"Please choose the latest tag: ",
76-
choices=get_all_tags(),
76+
choices=get_tag_names(),
7777
style=self.cz.style,
7878
).ask()
7979

commitizen/git.py

Lines changed: 84 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,37 @@
66
from commitizen import cmd
77

88

9+
class GitObject:
10+
def __eq__(self, other):
11+
if not isinstance(other, GitObject):
12+
return False
13+
return self.rev == other.rev
14+
15+
16+
class GitCommit(GitObject):
17+
def __init__(self, rev, title, body=""):
18+
self.rev = rev.strip()
19+
self.title = title.strip()
20+
self.body = body.strip()
21+
22+
@property
23+
def message(self):
24+
return f"{self.title}\n\n{self.body}"
25+
26+
def __repr__(self):
27+
return f"{self.title} ({self.rev})"
28+
29+
30+
class GitTag(GitObject):
31+
def __init__(self, name, rev, date):
32+
self.rev = rev.strip()
33+
self.name = name.strip()
34+
self.date = date.strip()
35+
36+
def __repr__(self):
37+
return f"{self.name} ({self.rev})"
38+
39+
940
def tag(tag: str):
1041
c = cmd.run(f"git tag {tag}")
1142
return c
@@ -20,38 +51,69 @@ def commit(message: str, args=""):
2051
return c
2152

2253

23-
def get_commits(start: str, end: str = "HEAD", from_beginning: bool = False) -> list:
54+
def get_commits(
55+
start: Optional[str] = None,
56+
end: str = "HEAD",
57+
*,
58+
log_format: str = "%H%n%s%n%b",
59+
delimiter: str = "----------commit-delimiter----------",
60+
) -> List[GitCommit]:
61+
"""
62+
Get the commits betweeen start and end
63+
"""
64+
git_log_cmd = f"git log --pretty={log_format}{delimiter}"
2465

25-
c = cmd.run(f"git log --pretty=format:%s%n%b {start}...{end}")
26-
27-
if from_beginning:
28-
c = cmd.run(f"git log --pretty=format:%s%n%b {end}")
66+
if start:
67+
c = cmd.run(f"{git_log_cmd} {start}...{end}")
68+
else:
69+
c = cmd.run(f"{git_log_cmd} {end}")
2970

3071
if not c.out:
3172
return []
32-
return c.out.split("\n")
73+
74+
git_commits = []
75+
for rev_and_commit in c.out.split(delimiter):
76+
rev_and_commit = rev_and_commit.strip()
77+
if not rev_and_commit:
78+
continue
79+
rev, title, *body_list = rev_and_commit.split("\n")
80+
81+
if rev_and_commit:
82+
git_commit = GitCommit(
83+
rev=rev.strip(), title=title.strip(), body="\n".join(body_list).strip()
84+
)
85+
git_commits.append(git_commit)
86+
return git_commits
87+
88+
89+
def get_tags(dateformat: str = "%Y-%m-%d") -> List[GitTag]:
90+
inner_delimiter = "---inner_delimiter---"
91+
formatter = (
92+
f"'%(refname:lstrip=2){inner_delimiter}"
93+
f"%(objectname){inner_delimiter}"
94+
f"%(committerdate:format:{dateformat})'"
95+
)
96+
c = cmd.run(f"git tag --format={formatter} --sort=-committerdate")
97+
if c.err or not c.out:
98+
return []
99+
100+
git_tags = [GitTag(*line.split(inner_delimiter)) for line in c.out.split("\n")[:-1]]
101+
return git_tags
33102

34103

35104
def tag_exist(tag: str) -> bool:
36105
c = cmd.run(f"git tag --list {tag}")
37106
return tag in c.out
38107

39108

40-
def is_staging_clean() -> bool:
41-
"""Check if staing is clean"""
42-
c = cmd.run("git diff --no-ext-diff --name-only")
43-
c_cached = cmd.run("git diff --no-ext-diff --cached --name-only")
44-
return not (bool(c.out) or bool(c_cached.out))
45-
46-
47-
def get_latest_tag() -> Optional[str]:
109+
def get_latest_tag_name() -> Optional[str]:
48110
c = cmd.run("git describe --abbrev=0 --tags")
49111
if c.err:
50112
return None
51113
return c.out.strip()
52114

53115

54-
def get_all_tags() -> Optional[List[str]]:
116+
def get_tag_names() -> Optional[List[str]]:
55117
c = cmd.run("git tag --list")
56118
if c.err:
57119
return []
@@ -63,3 +125,10 @@ def find_git_project_root() -> Optional[Path]:
63125
if not c.err:
64126
return Path(c.out.strip())
65127
return None
128+
129+
130+
def is_staging_clean() -> bool:
131+
"""Check if staing is clean"""
132+
c = cmd.run("git diff --no-ext-diff --name-only")
133+
c_cached = cmd.run("git diff --no-ext-diff --cached --name-only")
134+
return not (bool(c.out) or bool(c_cached.out))

tests/commands/test_bump_command.py

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,6 @@
88
from commitizen import cli, cmd, git
99

1010

11-
@pytest.fixture(scope="function")
12-
def tmp_git_project(tmpdir):
13-
with tmpdir.as_cwd():
14-
with open("pyproject.toml", "w") as f:
15-
f.write("[tool.commitizen]\n" 'version="0.1.0"')
16-
17-
cmd.run("git init")
18-
19-
yield
20-
21-
2211
def create_file_and_commit(message: str, filename: Optional[str] = None):
2312
if not filename:
2413
filename = str(uuid.uuid4())
@@ -28,7 +17,7 @@ def create_file_and_commit(message: str, filename: Optional[str] = None):
2817
git.commit(message)
2918

3019

31-
@pytest.mark.usefixtures("tmp_git_project")
20+
@pytest.mark.usefixtures("tmp_commitizen_project")
3221
def test_bump_command(mocker):
3322
# MINOR
3423
create_file_and_commit("feat: new file")
@@ -101,12 +90,12 @@ def test_bump_when_bumpping_is_not_support(mocker, capsys, tmpdir):
10190
assert "'cz_jira' rule does not support bump" in err
10291

10392

104-
def test_bump_is_not_specify(mocker, capsys, tmpdir):
93+
@pytest.mark.usefixtures("tmp_git_project")
94+
def test_bump_is_not_specify(mocker, capsys):
10595
mocker.patch.object(sys, "argv", ["cz", "bump"])
10696

10797
with pytest.raises(SystemExit):
108-
with tmpdir.as_cwd():
109-
cli.main()
98+
cli.main()
11099

111100
expected_error_message = (
112101
"[NO_VERSION_SPECIFIED]\n"
@@ -118,7 +107,8 @@ def test_bump_is_not_specify(mocker, capsys, tmpdir):
118107
assert expected_error_message in err
119108

120109

121-
def test_bump_when_not_new_commit(mocker, capsys, tmp_git_project):
110+
@pytest.mark.usefixtures("tmp_commitizen_project")
111+
def test_bump_when_not_new_commit(mocker, capsys):
122112
testargs = ["cz", "bump", "--yes"]
123113
mocker.patch.object(sys, "argv", testargs)
124114

0 commit comments

Comments
 (0)