Skip to content

Commit cbe8f11

Browse files
authored
Merge pull request #201 from commitizen-tools/refactor-error-code
refactor: use custom exception for error handling
2 parents fa681af + 32287f0 commit cbe8f11

26 files changed

+565
-215
lines changed

commitizen/bump.py

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

77
from packaging.version import Version
88

9-
from commitizen import out
109
from commitizen.defaults import (
1110
MAJOR,
1211
MINOR,
@@ -15,7 +14,7 @@
1514
bump_message,
1615
bump_pattern,
1716
)
18-
from commitizen.error_codes import CURRENT_VERSION_NOT_FOUND
17+
from commitizen.exceptions import CurrentVersionNotFoundError
1918
from commitizen.git import GitCommit
2019

2120

@@ -162,12 +161,11 @@ def update_version_in_files(
162161
file_content.append(line)
163162

164163
if check_consistency and not current_version_found:
165-
out.error(
164+
raise CurrentVersionNotFoundError(
166165
f"Current version {current_version} is not found in {location}.\n"
167166
"The version defined in commitizen configuration and the ones in "
168167
"version_files are possibly inconsistent."
169168
)
170-
raise SystemExit(CURRENT_VERSION_NOT_FOUND)
171169

172170
# Write the file out again
173171
with open(filepath, "w") as file:

commitizen/cli.py

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
import logging
33
import sys
44
import warnings
5+
from functools import partial
56

67
from decli import cli
78

8-
from commitizen import commands, config, out
9+
from commitizen import commands, config
10+
from commitizen.exceptions import CommitizenException, ExpectedExit, NoCommandFoundError
911

1012
logger = logging.getLogger(__name__)
1113
data = {
@@ -237,6 +239,24 @@
237239
},
238240
}
239241

242+
original_excepthook = sys.excepthook
243+
244+
245+
def commitizen_excepthook(type, value, tracekback, debug=False):
246+
if isinstance(value, CommitizenException):
247+
if value.message:
248+
value.output_method(value.message)
249+
if debug:
250+
original_excepthook(type, value, tracekback)
251+
sys.exit(value.exit_code)
252+
else:
253+
original_excepthook(type, value, tracekback)
254+
255+
256+
commitizen_debug_excepthook = partial(commitizen_excepthook, debug=True)
257+
258+
sys.excepthook = commitizen_excepthook
259+
240260

241261
def main():
242262
conf = config.read_cfg()
@@ -245,14 +265,13 @@ def main():
245265
# Show help if no arg provided
246266
if len(sys.argv) == 1:
247267
parser.print_help(sys.stderr)
248-
raise SystemExit()
268+
raise ExpectedExit()
249269

250270
# This is for the command required constraint in 2.0
251271
try:
252272
args = parser.parse_args()
253273
except TypeError:
254-
out.error("Command is required")
255-
raise SystemExit()
274+
raise NoCommandFoundError()
256275

257276
if args.name:
258277
conf.update({"name": args.name})
@@ -270,19 +289,16 @@ def main():
270289
args.func = commands.Version
271290

272291
if args.debug:
273-
warnings.warn(
274-
(
275-
"Debug will be deprecated in next major version. "
276-
"Please remove it from your scripts"
277-
),
278-
category=DeprecationWarning,
279-
)
280292
logging.getLogger("commitizen").setLevel(logging.DEBUG)
293+
sys.excepthook = commitizen_debug_excepthook
281294

282295
# TODO: This try block can be removed after command is required in 2.0
283296
# Handle the case that argument is given, but no command is provided
284297
try:
285298
args.func(conf, vars(args))()
286299
except AttributeError:
287-
out.error("Command is required")
288-
raise SystemExit()
300+
raise NoCommandFoundError()
301+
302+
303+
if __name__ == "__main__":
304+
main()

commitizen/commands/bump.py

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
from commitizen import bump, factory, git, out
77
from commitizen.commands.changelog import Changelog
88
from commitizen.config import BaseConfig
9-
from commitizen.error_codes import (
10-
COMMIT_FAILED,
11-
NO_COMMITS_FOUND,
12-
NO_PATTERN_MAP,
13-
NO_VERSION_SPECIFIED,
14-
TAG_FAILED,
9+
from commitizen.exceptions import (
10+
BumpCommitFailedError,
11+
BumpTagFailedError,
12+
DryRunExit,
13+
ExpectedExit,
14+
NoCommitsFoundError,
15+
NoPatternMapError,
16+
NoVersionSpecifiedError,
1517
)
1618

1719

@@ -56,8 +58,9 @@ def find_increment(self, commits: List[git.GitCommit]) -> Optional[str]:
5658
bump_pattern = self.cz.bump_pattern
5759
bump_map = self.cz.bump_map
5860
if not bump_map or not bump_pattern:
59-
out.error(f"'{self.config.settings['name']}' rule does not support bump")
60-
raise SystemExit(NO_PATTERN_MAP)
61+
raise NoPatternMapError(
62+
f"'{self.config.settings['name']}' rule does not support bump"
63+
)
6164
increment = bump.find_increment(
6265
commits, regex=bump_pattern, increments_map=bump_map
6366
)
@@ -68,12 +71,7 @@ def __call__(self): # noqa: C901
6871
try:
6972
current_version_instance: Version = Version(self.bump_settings["version"])
7073
except TypeError:
71-
out.error(
72-
"[NO_VERSION_SPECIFIED]\n"
73-
"Check if current version is specified in config file, like:\n"
74-
"version = 0.4.3\n"
75-
)
76-
raise SystemExit(NO_VERSION_SPECIFIED)
74+
raise NoVersionSpecifiedError()
7775

7876
# Initialize values from sources (conf)
7977
current_version: str = self.config.settings["version"]
@@ -101,8 +99,7 @@ def __call__(self): # noqa: C901
10199
# No commits, there is no need to create an empty tag.
102100
# Unless we previously had a prerelease.
103101
if not commits and not current_version_instance.is_prerelease:
104-
out.error("[NO_COMMITS_FOUND]\n" "No new commits found.")
105-
raise SystemExit(NO_COMMITS_FOUND)
102+
raise NoCommitsFoundError("[NO_COMMITS_FOUND]\n" "No new commits found.")
106103

107104
if increment is None:
108105
increment = self.find_increment(commits)
@@ -129,7 +126,7 @@ def __call__(self): # noqa: C901
129126

130127
# Do not perform operations over files or git.
131128
if dry_run:
132-
raise SystemExit()
129+
raise DryRunExit()
133130

134131
bump.update_version_in_files(
135132
current_version,
@@ -138,7 +135,7 @@ def __call__(self): # noqa: C901
138135
check_consistency=self.check_consistency,
139136
)
140137
if is_files_only:
141-
raise SystemExit()
138+
raise ExpectedExit()
142139

143140
if self.changelog:
144141
changelog = Changelog(
@@ -154,12 +151,10 @@ def __call__(self): # noqa: C901
154151
self.config.set_key("version", new_version.public)
155152
c = git.commit(message, args=self._get_commit_args())
156153
if c.err:
157-
out.error('git.commit error: "{}"'.format(c.err.strip()))
158-
raise SystemExit(COMMIT_FAILED)
154+
raise BumpCommitFailedError(f'git.commit error: "{c.err.strip()}"')
159155
c = git.tag(new_tag_version)
160156
if c.err:
161-
out.error(c.err)
162-
raise SystemExit(TAG_FAILED)
157+
raise BumpTagFailedError(c.err)
163158
out.success("Done!")
164159

165160
def _get_commit_args(self):

commitizen/commands/changelog.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55

66
from commitizen import changelog, factory, git, out
77
from commitizen.config import BaseConfig
8-
from commitizen.error_codes import NO_COMMITS_FOUND, NO_PATTERN_MAP, NO_REVISION
8+
from commitizen.exceptions import (
9+
DryRunExit,
10+
NoCommitsFoundError,
11+
NoPatternMapError,
12+
NoRevisionError,
13+
)
914
from commitizen.git import GitTag
1015

1116

@@ -51,9 +56,9 @@ def _find_incremental_rev(self, latest_version: str, tags: List[GitTag]) -> str:
5156
try:
5257
score, tag = max(tag_ratio, key=itemgetter(0))
5358
except ValueError:
54-
raise SystemExit(NO_REVISION)
59+
raise NoRevisionError()
5560
if score < SIMILARITY_THRESHOLD:
56-
raise SystemExit(NO_REVISION)
61+
raise NoRevisionError()
5762
start_rev = tag.name
5863
return start_rev
5964

@@ -68,12 +73,10 @@ def __call__(self):
6873
Callable
6974
] = self.cz.changelog_message_builder_hook
7075
changelog_hook: Optional[Callable] = self.cz.changelog_hook
71-
7276
if not changelog_pattern or not commit_parser:
73-
out.error(
77+
raise NoPatternMapError(
7478
f"'{self.config.settings['name']}' rule does not support changelog"
7579
)
76-
raise SystemExit(NO_PATTERN_MAP)
7780

7881
tags = git.get_tags()
7982
if not tags:
@@ -87,8 +90,7 @@ def __call__(self):
8790

8891
commits = git.get_commits(start=start_rev, args="--author-date-order")
8992
if not commits:
90-
out.error("No commits found")
91-
raise SystemExit(NO_COMMITS_FOUND)
93+
raise NoCommitsFoundError("No commits found")
9294

9395
tree = changelog.generate_tree_from_commits(
9496
commits,
@@ -104,7 +106,7 @@ def __call__(self):
104106

105107
if self.dry_run:
106108
out.write(changelog_out)
107-
raise SystemExit(0)
109+
raise DryRunExit()
108110

109111
lines = []
110112
if self.incremental and os.path.isfile(self.file_name):

commitizen/commands/check.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import os
22
import re
3-
import warnings
43
from typing import Dict, Optional
54

65
from commitizen import factory, git, out
76
from commitizen.config import BaseConfig
8-
from commitizen.error_codes import INVALID_COMMIT_MSG, NO_COMMITS_FOUND
7+
from commitizen.exceptions import (
8+
InvalidCommandArgumentError,
9+
InvalidCommitMessageError,
10+
NoCommitsFoundError,
11+
)
912

1013

1114
class Check:
@@ -29,35 +32,32 @@ def __init__(self, config: BaseConfig, arguments: Dict[str, str], cwd=os.getcwd(
2932

3033
def _valid_command_argument(self):
3134
if bool(self.commit_msg_file) is bool(self.rev_range):
32-
out.error(
35+
raise InvalidCommandArgumentError(
3336
(
3437
"One and only one argument is required for check command! "
3538
"See 'cz check -h' for more information"
3639
)
3740
)
38-
raise SystemExit()
3941

4042
def __call__(self):
4143
"""Validate if commit messages follows the conventional pattern.
4244
4345
Raises:
44-
SystemExit: if the commit provided not follows the conventional pattern
46+
InvalidCommitMessageError: if the commit provided not follows the conventional pattern
4547
"""
4648
commit_msgs = self._get_commit_messages()
4749
if not commit_msgs:
48-
warnings.warn(f"No commit found with range: '{self.rev_range}'")
49-
raise SystemExit(NO_COMMITS_FOUND)
50+
raise NoCommitsFoundError(f"No commit found with range: '{self.rev_range}'")
5051

5152
pattern = self.cz.schema_pattern()
5253
for commit_msg in commit_msgs:
5354
if not Check.validate_commit_message(commit_msg, pattern):
54-
out.error(
55+
raise InvalidCommitMessageError(
5556
"commit validation: failed!\n"
5657
"please enter a commit message in the commitizen format.\n"
5758
f"commit: {commit_msg}\n"
5859
f"pattern: {pattern}"
5960
)
60-
raise SystemExit(INVALID_COMMIT_MSG)
6161
out.success("Commit validation: successful!")
6262

6363
def _get_commit_messages(self):

commitizen/commands/commit.py

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@
77
from commitizen import factory, git, out
88
from commitizen.config import BaseConfig
99
from commitizen.cz.exceptions import CzException
10-
from commitizen.error_codes import (
11-
COMMIT_ERROR,
12-
CUSTOM_ERROR,
13-
NO_ANSWERS,
14-
NO_COMMIT_BACKUP,
15-
NOTHING_TO_COMMIT,
10+
from commitizen.exceptions import (
11+
CommitError,
12+
CustomError,
13+
DryRunExit,
14+
NoAnswersError,
15+
NoCommitBackupError,
16+
NothingToCommitError,
1617
)
1718

1819

@@ -28,8 +29,7 @@ def __init__(self, config: BaseConfig, arguments: dict):
2829
def read_backup_message(self) -> str:
2930
# Check the commit backup file exists
3031
if not os.path.isfile(self.temp_file):
31-
out.error("No commit backup found")
32-
raise SystemExit(NO_COMMIT_BACKUP)
32+
raise NoCommitBackupError()
3333

3434
# Read commit message from backup
3535
with open(self.temp_file, "r") as f:
@@ -44,20 +44,18 @@ def prompt_commit_questions(self) -> str:
4444
except ValueError as err:
4545
root_err = err.__context__
4646
if isinstance(root_err, CzException):
47-
out.error(root_err.__str__())
48-
raise SystemExit(CUSTOM_ERROR)
47+
raise CustomError(root_err.__str__())
4948
raise err
5049

5150
if not answers:
52-
raise SystemExit(NO_ANSWERS)
51+
raise NoAnswersError()
5352
return cz.message(answers)
5453

5554
def __call__(self):
5655
dry_run: bool = self.arguments.get("dry_run")
5756

5857
if git.is_staging_clean() and not dry_run:
59-
out.write("No files added to staging!")
60-
raise SystemExit(NOTHING_TO_COMMIT)
58+
raise NothingToCommitError("No files added to staging!")
6159

6260
retry: bool = self.arguments.get("retry")
6361

@@ -69,7 +67,7 @@ def __call__(self):
6967
out.info(f"\n{m}\n")
7068

7169
if dry_run:
72-
raise SystemExit(NOTHING_TO_COMMIT)
70+
raise DryRunExit()
7371

7472
c = git.commit(m)
7573

@@ -80,7 +78,7 @@ def __call__(self):
8078
with open(self.temp_file, "w") as f:
8179
f.write(m)
8280

83-
raise SystemExit(COMMIT_ERROR)
81+
raise CommitError()
8482

8583
if "nothing added" in c.out or "no changes added to commit" in c.out:
8684
out.error(c.out)

0 commit comments

Comments
 (0)