Skip to content

Commit c688f78

Browse files
authored
Merge pull request commitizen-tools#540 from bhelgs/git_get_commits_error_check
git.get_commits error check
2 parents 43473c4 + 7562808 commit c688f78

File tree

9 files changed

+89
-37
lines changed

9 files changed

+89
-37
lines changed

commitizen/changelog.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535

3636
from commitizen import defaults
3737
from commitizen.bump import normalize_tag
38-
from commitizen.exceptions import InvalidConfigurationError
38+
from commitizen.exceptions import InvalidConfigurationError, NoCommitsFoundError
3939
from commitizen.git import GitCommit, GitTag
4040

4141

@@ -309,7 +309,7 @@ def get_oldest_and_newest_rev(
309309

310310
tags_range = get_smart_tag_range(tags, newest=newest_tag, oldest=oldest_tag)
311311
if not tags_range:
312-
return None, None
312+
raise NoCommitsFoundError("Could not find a valid revision range.")
313313

314314
oldest_rev: Optional[str] = tags_range[-1].name
315315
newest_rev = newest_tag

commitizen/commands/changelog.py

-4
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@
1616
from commitizen.git import GitTag, smart_open
1717

1818

19-
def similar(a, b):
20-
return SequenceMatcher(None, a, b).ratio()
21-
22-
2319
class Changelog:
2420
"""Generate a changelog based on the commit history."""
2521

commitizen/exceptions.py

+5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class ExitCode(enum.IntEnum):
2727
NOT_ALLOWED = 20
2828
NO_INCREMENT = 21
2929
UNRECOGNIZED_CHARACTERSET_ENCODING = 22
30+
GIT_COMMAND_ERROR = 23
3031

3132

3233
class CommitizenException(Exception):
@@ -153,3 +154,7 @@ class NotAllowed(CommitizenException):
153154

154155
class CharacterSetDecodeError(CommitizenException):
155156
exit_code = ExitCode.UNRECOGNIZED_CHARACTERSET_ENCODING
157+
158+
159+
class GitCommandError(CommitizenException):
160+
exit_code = ExitCode.GIT_COMMAND_ERROR

commitizen/git.py

+29-17
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
from tempfile import NamedTemporaryFile
66
from typing import List, Optional
77

8-
from commitizen import cmd
8+
from commitizen import cmd, out
9+
from commitizen.exceptions import GitCommandError
910

1011
UNIX_EOL = "\n"
1112
WINDOWS_EOL = "\r\n"
@@ -104,25 +105,12 @@ def get_commits(
104105
start: Optional[str] = None,
105106
end: str = "HEAD",
106107
*,
107-
log_format: str = "%H%n%s%n%an%n%ae%n%b",
108-
delimiter: str = "----------commit-delimiter----------",
109108
args: str = "",
110109
) -> List[GitCommit]:
111110
"""Get the commits between start and end."""
112-
git_log_cmd = (
113-
f"git -c log.showSignature=False log --pretty={log_format}{delimiter} {args}"
114-
)
115-
116-
if start:
117-
command = f"{git_log_cmd} {start}..{end}"
118-
else:
119-
command = f"{git_log_cmd} {end}"
120-
c = cmd.run(command)
121-
if not c.out:
122-
return []
123-
111+
git_log_entries = _get_log_as_str_list(start, end, args)
124112
git_commits = []
125-
for rev_and_commit in c.out.split(f"{delimiter}\n"):
113+
for rev_and_commit in git_log_entries:
126114
if not rev_and_commit:
127115
continue
128116
rev, title, author, author_email, *body_list = rev_and_commit.split("\n")
@@ -147,8 +135,13 @@ def get_tags(dateformat: str = "%Y-%m-%d") -> List[GitTag]:
147135
f'%(object)"'
148136
)
149137
c = cmd.run(f"git tag --format={formatter} --sort=-creatordate")
138+
if c.return_code != 0:
139+
raise GitCommandError(c.err)
140+
141+
if c.err:
142+
out.warn(f"Attempting to proceed after: {c.err}")
150143

151-
if c.err or not c.out:
144+
if not c.out:
152145
return []
153146

154147
git_tags = [
@@ -228,3 +221,22 @@ def get_eol_style() -> EOLTypes:
228221
def smart_open(*args, **kargs):
229222
"""Open a file with the EOL style determined from Git."""
230223
return open(*args, newline=get_eol_style().get_eol_for_open(), **kargs)
224+
225+
226+
def _get_log_as_str_list(start: Optional[str], end: str, args: str) -> List[str]:
227+
"""Get string representation of each log entry"""
228+
delimiter = "----------commit-delimiter----------"
229+
log_format: str = "%H%n%s%n%an%n%ae%n%b"
230+
git_log_cmd = (
231+
f"git -c log.showSignature=False log --pretty={log_format}{delimiter} {args}"
232+
)
233+
if start:
234+
command = f"{git_log_cmd} {start}..{end}"
235+
else:
236+
command = f"{git_log_cmd} {end}"
237+
c = cmd.run(command)
238+
if c.return_code != 0:
239+
raise GitCommandError(c.err)
240+
if not c.out:
241+
return []
242+
return c.out.split(f"{delimiter}\n")

docs/exit_codes.md

+1
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ These exit codes can be found in `commitizen/exceptions.py::ExitCode`.
3030
| NotAllowed | 20 | `--incremental` cannot be combined with a `rev_range` |
3131
| NoneIncrementExit | 21 | The commits found are not eligible to be bumped |
3232
| CharacterSetDecodeError | 22 | The character encoding of the command output could not be determined |
33+
| GitCommandError | 23 | Unexpected failure while calling a git command |

tests/commands/test_bump_command.py

+10
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,19 @@ def test_bump_when_version_is_not_specify(mocker):
273273

274274
@pytest.mark.usefixtures("tmp_commitizen_project")
275275
def test_bump_when_no_new_commit(mocker):
276+
"""bump without any commits since the last bump."""
277+
# We need this first commit otherwise the revision is invalid.
278+
create_file_and_commit("feat: initial")
279+
276280
testargs = ["cz", "bump", "--yes"]
277281
mocker.patch.object(sys, "argv", testargs)
278282

283+
# First bump.
284+
# The next bump should fail since
285+
# there is not a commit between the two bumps.
286+
cli.main()
287+
288+
# bump without a new commit.
279289
with pytest.raises(NoCommitsFoundError) as excinfo:
280290
cli.main()
281291

tests/commands/test_changelog_command.py

+25-13
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,6 @@
1515
from tests.utils import create_file_and_commit, wait_for_tag
1616

1717

18-
@pytest.mark.usefixtures("tmp_commitizen_project")
19-
def test_changelog_on_empty_project(mocker):
20-
testargs = ["cz", "changelog", "--dry-run"]
21-
mocker.patch.object(sys, "argv", testargs)
22-
23-
with pytest.raises(NoCommitsFoundError) as excinfo:
24-
cli.main()
25-
26-
assert "No commits found" in str(excinfo)
27-
28-
2918
@pytest.mark.usefixtures("tmp_commitizen_project")
3019
def test_changelog_from_version_zero_point_two(mocker, capsys, file_regression):
3120
create_file_and_commit("feat: new file")
@@ -351,6 +340,15 @@ def test_changelog_without_revision(mocker, tmp_commitizen_project):
351340
cli.main()
352341

353342

343+
def test_changelog_incremental_with_revision(mocker):
344+
"""combining incremental with a revision doesn't make sense"""
345+
testargs = ["cz", "changelog", "--incremental", "0.2.0"]
346+
mocker.patch.object(sys, "argv", testargs)
347+
348+
with pytest.raises(NotAllowed):
349+
cli.main()
350+
351+
354352
def test_changelog_with_different_tag_name_and_changelog_content(
355353
mocker, tmp_commitizen_project
356354
):
@@ -633,6 +631,7 @@ def test_changelog_from_rev_latest_version_from_arg(
633631
def test_changelog_from_rev_single_version_not_found(
634632
mocker, config_path, changelog_path
635633
):
634+
"""Provides an invalid revision ID to changelog command"""
636635
with open(config_path, "a") as f:
637636
f.write('tag_format = "$version"\n')
638637

@@ -657,12 +656,13 @@ def test_changelog_from_rev_single_version_not_found(
657656
with pytest.raises(NoCommitsFoundError) as excinfo:
658657
cli.main()
659658

660-
assert "No commits found" in str(excinfo)
659+
assert "Could not find a valid revision" in str(excinfo)
661660

662661

663662
@pytest.mark.usefixtures("tmp_commitizen_project")
664663
@pytest.mark.freeze_time("2022-02-13")
665664
def test_changelog_from_rev_range_version_not_found(mocker, config_path):
665+
"""Provides an invalid end revision ID to changelog command"""
666666
with open(config_path, "a") as f:
667667
f.write('tag_format = "$version"\n')
668668

@@ -684,7 +684,7 @@ def test_changelog_from_rev_range_version_not_found(mocker, config_path):
684684
with pytest.raises(NoCommitsFoundError) as excinfo:
685685
cli.main()
686686

687-
assert "No commits found" in str(excinfo)
687+
assert "Could not find a valid revision" in str(excinfo)
688688

689689

690690
@pytest.mark.usefixtures("tmp_commitizen_project")
@@ -916,3 +916,15 @@ def test_changelog_with_customized_change_type_order(
916916
out = f.read()
917917

918918
file_regression.check(out, extension=".md")
919+
920+
921+
@pytest.mark.usefixtures("tmp_commitizen_project")
922+
def test_empty_commit_list(mocker):
923+
create_file_and_commit("feat: a new world")
924+
925+
# test changelog properly handles when no commits are found for the revision
926+
mocker.patch("commitizen.git.get_commits", return_value=[])
927+
testargs = ["cz", "changelog"]
928+
mocker.patch.object(sys, "argv", testargs)
929+
with pytest.raises(NoCommitsFoundError):
930+
cli.main()

tests/commands/test_check_command.py

+6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
InvalidCommitMessageError,
1111
NoCommitsFoundError,
1212
)
13+
from tests.utils import create_file_and_commit
1314

1415
COMMIT_LOG = [
1516
"refactor: A code change that neither fixes a bug nor adds a feature",
@@ -217,7 +218,12 @@ def test_check_command_with_invalid_argument(config):
217218
)
218219

219220

221+
@pytest.mark.usefixtures("tmp_commitizen_project")
220222
def test_check_command_with_empty_range(config, mocker):
223+
224+
# must initialize git with a commit
225+
create_file_and_commit("feat: initial")
226+
221227
check_cmd = commands.Check(config=config, arguments={"rev_range": "master..master"})
222228
with pytest.raises(NoCommitsFoundError) as excinfo:
223229
check_cmd()

tests/test_git.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import pytest
77

8-
from commitizen import cmd, git
8+
from commitizen import cmd, exceptions, git
99
from tests.utils import FakeCommand, create_file_and_commit
1010

1111

@@ -58,6 +58,16 @@ def test_git_message_with_empty_body():
5858
assert commit.message == commit_title
5959

6060

61+
@pytest.mark.usefixtures("tmp_commitizen_project")
62+
def test_get_log_as_str_list_empty():
63+
"""ensure an exception or empty list in an empty project"""
64+
try:
65+
gitlog = git._get_log_as_str_list(start=None, end="HEAD", args="")
66+
except exceptions.GitCommandError:
67+
return
68+
assert len(gitlog) == 0, "list should be empty if no assert"
69+
70+
6171
@pytest.mark.usefixtures("tmp_commitizen_project")
6272
def test_get_commits():
6373
create_file_and_commit("feat(users): add username")

0 commit comments

Comments
 (0)