Skip to content

Commit 1570947

Browse files
authored
Merge pull request #489 from commitizen-tools/feat/485-no-raise
2 parents 605b125 + 8c2a6f4 commit 1570947

File tree

9 files changed

+200
-43
lines changed

9 files changed

+200
-43
lines changed

commitizen/cli.py

+51-4
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@
22
import logging
33
import sys
44
from functools import partial
5+
from typing import List
56

67
import argcomplete
78
from decli import cli
89

9-
from commitizen import commands, config
10-
from commitizen.exceptions import CommitizenException, ExpectedExit, NoCommandFoundError
10+
from commitizen import commands, config, out
11+
from commitizen.exceptions import (
12+
CommitizenException,
13+
ExitCode,
14+
ExpectedExit,
15+
NoCommandFoundError,
16+
)
1117

1218
logger = logging.getLogger(__name__)
1319
data = {
@@ -24,6 +30,12 @@
2430
"name": ["-n", "--name"],
2531
"help": "use the given commitizen (default: cz_conventional_commits)",
2632
},
33+
{
34+
"name": ["-nr", "--no-raise"],
35+
"type": str,
36+
"required": False,
37+
"help": "comma separated error codes that won't rise error, e.g: cz -nr 1,2,3 bump. See codes at https://commitizen-tools.github.io/commitizen/exit_codes/",
38+
},
2739
],
2840
"subcommands": {
2941
"title": "commands",
@@ -274,13 +286,20 @@
274286
original_excepthook = sys.excepthook
275287

276288

277-
def commitizen_excepthook(type, value, tracekback, debug=False):
289+
def commitizen_excepthook(
290+
type, value, tracekback, debug=False, no_raise: List[int] = None
291+
):
292+
if not no_raise:
293+
no_raise = []
278294
if isinstance(value, CommitizenException):
279295
if value.message:
280296
value.output_method(value.message)
281297
if debug:
282298
original_excepthook(type, value, tracekback)
283-
sys.exit(value.exit_code)
299+
exit_code = value.exit_code
300+
if exit_code in no_raise:
301+
exit_code = 0
302+
sys.exit(exit_code)
284303
else:
285304
original_excepthook(type, value, tracekback)
286305

@@ -290,6 +309,28 @@ def commitizen_excepthook(type, value, tracekback, debug=False):
290309
sys.excepthook = commitizen_excepthook
291310

292311

312+
def parse_no_raise(comma_separated_no_raise: str) -> List[int]:
313+
"""Convert the given string to exit codes.
314+
315+
Receives digits and strings and outputs the parsed integer which
316+
represents the exit code found in exceptions.
317+
"""
318+
no_raise_items: List[str] = comma_separated_no_raise.split(",")
319+
no_raise_codes = []
320+
for item in no_raise_items:
321+
if item.isdecimal():
322+
no_raise_codes.append(int(item))
323+
continue
324+
try:
325+
exit_code = ExitCode[item.strip()]
326+
except KeyError:
327+
out.warn(f"WARN: no_raise key `{item}` does not exist. Skipping.")
328+
continue
329+
else:
330+
no_raise_codes.append(exit_code.value)
331+
return no_raise_codes
332+
333+
293334
def main():
294335
conf = config.read_cfg()
295336
parser = cli(data)
@@ -319,6 +360,12 @@ def main():
319360
if args.debug:
320361
logging.getLogger("commitizen").setLevel(logging.DEBUG)
321362
sys.excepthook = commitizen_debug_excepthook
363+
elif args.no_raise:
364+
no_raise_exit_codes = parse_no_raise(args.no_raise)
365+
no_raise_debug_excepthook = partial(
366+
commitizen_excepthook, no_raise=no_raise_exit_codes
367+
)
368+
sys.excepthook = no_raise_debug_excepthook
322369

323370
args.func(conf, vars(args))()
324371

commitizen/exceptions.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class ExitCode(enum.IntEnum):
2525
INVALID_COMMAND_ARGUMENT = 18
2626
INVALID_CONFIGURATION = 19
2727
NOT_ALLOWED = 20
28+
NO_INCREMENT = 21
2829

2930

3031
class CommitizenException(Exception):
@@ -56,7 +57,7 @@ class DryRunExit(ExpectedExit):
5657

5758

5859
class NoneIncrementExit(CommitizenException):
59-
exit_code = ExitCode.NO_COMMITS_FOUND
60+
exit_code = ExitCode.NO_INCREMENT
6061

6162

6263
class NoCommitizenFoundException(CommitizenException):

commitizen/out.py

+5
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,8 @@ def info(value: str) -> None:
3030

3131
def diagnostic(value: str):
3232
line(value, file=sys.stderr)
33+
34+
35+
def warn(value: str) -> None:
36+
message = colored(value, "magenta")
37+
line(message)

docs/README.md

+9-13
Original file line numberDiff line numberDiff line change
@@ -124,21 +124,20 @@ Read more about the `check` command [here](check.md).
124124

125125
### Help
126126

127-
```bash
127+
```sh
128128
$ cz --help
129-
usage: cz [-h] [--debug] [-n NAME] [--version]
130-
{init,commit,c,ls,example,info,schema,bump,changelog,ch,check,version}
131-
...
129+
usage: cz [-h] [--debug] [-n NAME] [-nr NO_RAISE] {init,commit,c,ls,example,info,schema,bump,changelog,ch,check,version} ...
132130

133131
Commitizen is a cli tool to generate conventional commits.
134132
For more information about the topic go to https://conventionalcommits.org/
135133

136134
optional arguments:
137135
-h, --help show this help message and exit
138136
--debug use debug mode
139-
-n NAME, --name NAME use the given commitizen (default:
140-
cz_conventional_commits)
141-
--version get the version of the installed commitizen
137+
-n NAME, --name NAME use the given commitizen (default: cz_conventional_commits)
138+
-nr NO_RAISE, --no-raise NO_RAISE
139+
comma separated error codes that won't rise error, e.g: cz -nr 1,2,3 bump. See codes at https://commitizen-
140+
tools.github.io/commitizen/exit_codes/
142141
143142
commands:
144143
{init,commit,c,ls,example,info,schema,bump,changelog,ch,check,version}
@@ -149,12 +148,9 @@ commands:
149148
info show information about the cz
150149
schema show commit schema
151150
bump bump semantic version based on the git log
152-
changelog (ch) generate changelog (note that it will overwrite
153-
existing file)
154-
check validates that a commit message matches the commitizen
155-
schema
156-
version get the version of the installed commitizen or the
157-
current project (default: installed commitizen)
151+
changelog (ch) generate changelog (note that it will overwrite existing file)
152+
check validates that a commit message matches the commitizen schema
153+
version get the version of the installed commitizen or the current project (default: installed commitizen)
158154
```
159155
160156
## Setting up bash completion

docs/bump.md

+63
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,69 @@ Example:
179179
cz bump --changelog --changelog-to-stdout > body.md
180180
```
181181

182+
## Avoid raising errors
183+
184+
Some situations from commitizen rise an exit code different than 0.
185+
If the error code is different than 0, any CI or script running commitizen might be interrupted.
186+
187+
If you have special use case, where you don't want one of this error codes to be raised, you can
188+
tell commitizen to not raise them.
189+
190+
### Recommended use case
191+
192+
At the moment, we've identified that the most common error code to skip is
193+
194+
| Error name | Exit code |
195+
| ----------------- | --------- |
196+
| NoneIncrementExit | 21 |
197+
198+
There are some situations where you don't want to get an error code when some
199+
commits do not match your rules, you just want those commits to be skipped.
200+
201+
```sh
202+
cz -nr 21 bump
203+
```
204+
205+
### Easy way
206+
207+
Check which error code was raised by commitizen by running in the terminal
208+
209+
```sh
210+
echo $?
211+
```
212+
213+
The output should be an integer like this
214+
215+
```sh
216+
3
217+
```
218+
219+
And then you can tell commitizen to ignore it:
220+
221+
```sh
222+
cz --no-raise 3
223+
```
224+
225+
You can tell commitizen to skip more than one if needed:
226+
227+
```sh
228+
cz --no-raise 3,4,5
229+
```
230+
231+
### Longer way
232+
233+
Check the list of [exit_codes](./exit_codes.md) and understand which one you have
234+
to skip and why.
235+
236+
Remember to document somewhere this, because you'll forget.
237+
238+
For example if the system raises a `NoneIncrementExit` error, you look it up
239+
on the list and then you can use the exit code:
240+
241+
```sh
242+
cz -nr 21 bump
243+
```
244+
182245
## Configuration
183246

184247
### `tag_format`

docs/exit_codes.md

+25-23
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,28 @@ Commitizen handles expected exceptions through `CommitizenException` and returns
44

55
These exit codes can be found in `commitizen/exceptions.py::ExitCode`.
66

7-
| Exception | Exit Code | Description |
8-
| --------- | --------- | ----------- |
9-
| ExpectedExit | 0 | Expected exit |
10-
| DryRunExit | 0 | Exit due to passing `--dry-run` option |
11-
| NoCommitizenFoundException | 1 | Using a cz (e.g., `cz_jira`) that cannot be found in your system |
12-
| NotAGitProjectError | 2 | Not in a git project |
13-
| NoCommitsFoundError | 3 | No commit found |
14-
| NoVersionSpecifiedError | 4 | Version can not be found in configuration file |
15-
| NoPatternMapError | 5 | bump / changelog pattern or map can not be found in configuration file |
16-
| BumpCommitFailedError | 6 | Commit error when bumping version |
17-
| BumpTagFailedError | 7 | Tag error when bumping version |
18-
| NoAnswersError | 8 | No user response given |
19-
| CommitError | 9 | git commit error |
20-
| NoCommitBackupError | 10 | Commit back up file cannot be found |
21-
| NothingToCommitError | 11 | Nothing in staging to be committed |
22-
| CustomError | 12 | `CzException` raised |
23-
| NoCommandFoundError | 13 | No command found when running commitizen cli (e.g., `cz --debug`) |
24-
| InvalidCommitMessageError | 14 | The commit message does not pass `cz check` |
25-
| MissingConfigError | 15 | Configuration missed for `cz_customize` |
26-
| NoRevisionError | 16 | No revision found |
27-
| CurrentVersionNotFoundError | 17 | current version cannot be found in *version_files* |
28-
| InvalidCommandArgumentError | 18 | The argument provide to command is invalid (e.g. `cz check -commit-msg-file filename --rev-range master..`) |
29-
| InvalidConfigurationError | 19 | An error was found in the Commitizen Configuration, such as duplicates in `change_type_order` |
7+
| Exception | Exit Code | Description |
8+
| --------------------------- | --------- | ----------------------------------------------------------------------------------------------------------- |
9+
| ExpectedExit | 0 | Expected exit |
10+
| DryRunExit | 0 | Exit due to passing `--dry-run` option |
11+
| NoCommitizenFoundException | 1 | Using a cz (e.g., `cz_jira`) that cannot be found in your system |
12+
| NotAGitProjectError | 2 | Not in a git project |
13+
| NoCommitsFoundError | 3 | No commit found |
14+
| NoVersionSpecifiedError | 4 | Version can not be found in configuration file |
15+
| NoPatternMapError | 5 | bump / changelog pattern or map can not be found in configuration file |
16+
| BumpCommitFailedError | 6 | Commit error when bumping version |
17+
| BumpTagFailedError | 7 | Tag error when bumping version |
18+
| NoAnswersError | 8 | No user response given |
19+
| CommitError | 9 | git commit error |
20+
| NoCommitBackupError | 10 | Commit back up file cannot be found |
21+
| NothingToCommitError | 11 | Nothing in staging to be committed |
22+
| CustomError | 12 | `CzException` raised |
23+
| NoCommandFoundError | 13 | No command found when running commitizen cli (e.g., `cz --debug`) |
24+
| InvalidCommitMessageError | 14 | The commit message does not pass `cz check` |
25+
| MissingConfigError | 15 | Configuration missed for `cz_customize` |
26+
| NoRevisionError | 16 | No revision found |
27+
| CurrentVersionNotFoundError | 17 | current version cannot be found in _version_files_ |
28+
| InvalidCommandArgumentError | 18 | The argument provide to command is invalid (e.g. `cz check -commit-msg-file filename --rev-range master..`) |
29+
| InvalidConfigurationError | 19 | An error was found in the Commitizen Configuration, such as duplicates in `change_type_order` |
30+
| NotAllowed | 20 | `--incremental` cannot be combined with a `rev_range` |
31+
| NoneIncrementExit | 21 | The commits found are not elegible to be bumped |

docs/tutorials/github_actions.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ the new tag, back to your master branch, we have to:
1212
with the following content.
1313

1414
!!! warning
15-
If you use `GITHUB_TOKEN` instead of `PERSONAL_ACCESS_TOKEN`, the job won't trigger another workflow. It's like using `[skip ci]` in other CI's.
15+
If you use `GITHUB_TOKEN` instead of `PERSONAL_ACCESS_TOKEN`, the job won't trigger another workflow. It's like using `[skip ci]` in other CI's.
1616

1717
```yaml
1818
name: Bump version

tests/commands/test_bump_command.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ def test_none_increment_should_not_call_git_tag_and_error_code_is_not_zero(
358358
cli.main()
359359
except NoneIncrementExit as e:
360360
git.tag.assert_not_called()
361-
assert e.exit_code == ExitCode.NO_COMMITS_FOUND
361+
assert e.exit_code == ExitCode.NO_INCREMENT
362362
raise e
363363

364364
# restore pop stashed

tests/test_cli.py

+43
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,46 @@ def test_argcomplete_activation():
9595
output = subprocess.run(["register-python-argcomplete", "cz"])
9696

9797
assert output.returncode == 0
98+
99+
100+
def test_commitizen_excepthook_no_raises(capsys):
101+
with pytest.raises(SystemExit) as excinfo:
102+
cli.commitizen_excepthook(
103+
NotAGitProjectError,
104+
NotAGitProjectError(),
105+
"",
106+
no_raise=[NotAGitProjectError.exit_code],
107+
)
108+
109+
assert excinfo.type == SystemExit
110+
assert excinfo.value.code == 0
111+
112+
113+
def test_parse_no_raise_single_integer():
114+
input_str = "1"
115+
result = cli.parse_no_raise(input_str)
116+
assert result == [1]
117+
118+
119+
def test_parse_no_raise_integers():
120+
input_str = "1,2,3"
121+
result = cli.parse_no_raise(input_str)
122+
assert result == [1, 2, 3]
123+
124+
125+
def test_parse_no_raise_error_code():
126+
input_str = "NO_COMMITIZEN_FOUND,NO_COMMITS_FOUND,NO_PATTERN_MAP"
127+
result = cli.parse_no_raise(input_str)
128+
assert result == [1, 3, 5]
129+
130+
131+
def test_parse_no_raise_mix_integer_error_code():
132+
input_str = "NO_COMMITIZEN_FOUND,2,NO_COMMITS_FOUND,4"
133+
result = cli.parse_no_raise(input_str)
134+
assert result == [1, 2, 3, 4]
135+
136+
137+
def test_parse_no_raise_mix_invalid_arg_is_skipped():
138+
input_str = "NO_COMMITIZEN_FOUND,2,nothing,4"
139+
result = cli.parse_no_raise(input_str)
140+
assert result == [1, 2, 4]

0 commit comments

Comments
 (0)