Skip to content

Commit

Permalink
Merge pull request #489 from commitizen-tools/feat/485-no-raise
Browse files Browse the repository at this point in the history
  • Loading branch information
woile authored Apr 15, 2022
2 parents 605b125 + 8c2a6f4 commit 1570947
Show file tree
Hide file tree
Showing 9 changed files with 200 additions and 43 deletions.
55 changes: 51 additions & 4 deletions commitizen/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@
import logging
import sys
from functools import partial
from typing import List

import argcomplete
from decli import cli

from commitizen import commands, config
from commitizen.exceptions import CommitizenException, ExpectedExit, NoCommandFoundError
from commitizen import commands, config, out
from commitizen.exceptions import (
CommitizenException,
ExitCode,
ExpectedExit,
NoCommandFoundError,
)

logger = logging.getLogger(__name__)
data = {
Expand All @@ -24,6 +30,12 @@
"name": ["-n", "--name"],
"help": "use the given commitizen (default: cz_conventional_commits)",
},
{
"name": ["-nr", "--no-raise"],
"type": str,
"required": False,
"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/",
},
],
"subcommands": {
"title": "commands",
Expand Down Expand Up @@ -274,13 +286,20 @@
original_excepthook = sys.excepthook


def commitizen_excepthook(type, value, tracekback, debug=False):
def commitizen_excepthook(
type, value, tracekback, debug=False, no_raise: List[int] = None
):
if not no_raise:
no_raise = []
if isinstance(value, CommitizenException):
if value.message:
value.output_method(value.message)
if debug:
original_excepthook(type, value, tracekback)
sys.exit(value.exit_code)
exit_code = value.exit_code
if exit_code in no_raise:
exit_code = 0
sys.exit(exit_code)
else:
original_excepthook(type, value, tracekback)

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


def parse_no_raise(comma_separated_no_raise: str) -> List[int]:
"""Convert the given string to exit codes.
Receives digits and strings and outputs the parsed integer which
represents the exit code found in exceptions.
"""
no_raise_items: List[str] = comma_separated_no_raise.split(",")
no_raise_codes = []
for item in no_raise_items:
if item.isdecimal():
no_raise_codes.append(int(item))
continue
try:
exit_code = ExitCode[item.strip()]
except KeyError:
out.warn(f"WARN: no_raise key `{item}` does not exist. Skipping.")
continue
else:
no_raise_codes.append(exit_code.value)
return no_raise_codes


def main():
conf = config.read_cfg()
parser = cli(data)
Expand Down Expand Up @@ -319,6 +360,12 @@ def main():
if args.debug:
logging.getLogger("commitizen").setLevel(logging.DEBUG)
sys.excepthook = commitizen_debug_excepthook
elif args.no_raise:
no_raise_exit_codes = parse_no_raise(args.no_raise)
no_raise_debug_excepthook = partial(
commitizen_excepthook, no_raise=no_raise_exit_codes
)
sys.excepthook = no_raise_debug_excepthook

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

Expand Down
3 changes: 2 additions & 1 deletion commitizen/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class ExitCode(enum.IntEnum):
INVALID_COMMAND_ARGUMENT = 18
INVALID_CONFIGURATION = 19
NOT_ALLOWED = 20
NO_INCREMENT = 21


class CommitizenException(Exception):
Expand Down Expand Up @@ -56,7 +57,7 @@ class DryRunExit(ExpectedExit):


class NoneIncrementExit(CommitizenException):
exit_code = ExitCode.NO_COMMITS_FOUND
exit_code = ExitCode.NO_INCREMENT


class NoCommitizenFoundException(CommitizenException):
Expand Down
5 changes: 5 additions & 0 deletions commitizen/out.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,8 @@ def info(value: str) -> None:

def diagnostic(value: str):
line(value, file=sys.stderr)


def warn(value: str) -> None:
message = colored(value, "magenta")
line(message)
22 changes: 9 additions & 13 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,21 +124,20 @@ Read more about the `check` command [here](check.md).

### Help

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

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

optional arguments:
-h, --help show this help message and exit
--debug use debug mode
-n NAME, --name NAME use the given commitizen (default:
cz_conventional_commits)
--version get the version of the installed commitizen
-n NAME, --name NAME use the given commitizen (default: cz_conventional_commits)
-nr NO_RAISE, --no-raise NO_RAISE
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/
commands:
{init,commit,c,ls,example,info,schema,bump,changelog,ch,check,version}
Expand All @@ -149,12 +148,9 @@ commands:
info show information about the cz
schema show commit schema
bump bump semantic version based on the git log
changelog (ch) generate changelog (note that it will overwrite
existing file)
check validates that a commit message matches the commitizen
schema
version get the version of the installed commitizen or the
current project (default: installed commitizen)
changelog (ch) generate changelog (note that it will overwrite existing file)
check validates that a commit message matches the commitizen schema
version get the version of the installed commitizen or the current project (default: installed commitizen)
```
## Setting up bash completion
Expand Down
63 changes: 63 additions & 0 deletions docs/bump.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,69 @@ Example:
cz bump --changelog --changelog-to-stdout > body.md
```

## Avoid raising errors

Some situations from commitizen rise an exit code different than 0.
If the error code is different than 0, any CI or script running commitizen might be interrupted.

If you have special use case, where you don't want one of this error codes to be raised, you can
tell commitizen to not raise them.

### Recommended use case

At the moment, we've identified that the most common error code to skip is

| Error name | Exit code |
| ----------------- | --------- |
| NoneIncrementExit | 21 |

There are some situations where you don't want to get an error code when some
commits do not match your rules, you just want those commits to be skipped.

```sh
cz -nr 21 bump
```

### Easy way

Check which error code was raised by commitizen by running in the terminal

```sh
echo $?
```

The output should be an integer like this

```sh
3
```

And then you can tell commitizen to ignore it:

```sh
cz --no-raise 3
```

You can tell commitizen to skip more than one if needed:

```sh
cz --no-raise 3,4,5
```

### Longer way

Check the list of [exit_codes](./exit_codes.md) and understand which one you have
to skip and why.

Remember to document somewhere this, because you'll forget.

For example if the system raises a `NoneIncrementExit` error, you look it up
on the list and then you can use the exit code:

```sh
cz -nr 21 bump
```

## Configuration

### `tag_format`
Expand Down
48 changes: 25 additions & 23 deletions docs/exit_codes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,28 @@ Commitizen handles expected exceptions through `CommitizenException` and returns

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

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

!!! warning
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.
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.

```yaml
name: Bump version
Expand Down
2 changes: 1 addition & 1 deletion tests/commands/test_bump_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ def test_none_increment_should_not_call_git_tag_and_error_code_is_not_zero(
cli.main()
except NoneIncrementExit as e:
git.tag.assert_not_called()
assert e.exit_code == ExitCode.NO_COMMITS_FOUND
assert e.exit_code == ExitCode.NO_INCREMENT
raise e

# restore pop stashed
Expand Down
43 changes: 43 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,46 @@ def test_argcomplete_activation():
output = subprocess.run(["register-python-argcomplete", "cz"])

assert output.returncode == 0


def test_commitizen_excepthook_no_raises(capsys):
with pytest.raises(SystemExit) as excinfo:
cli.commitizen_excepthook(
NotAGitProjectError,
NotAGitProjectError(),
"",
no_raise=[NotAGitProjectError.exit_code],
)

assert excinfo.type == SystemExit
assert excinfo.value.code == 0


def test_parse_no_raise_single_integer():
input_str = "1"
result = cli.parse_no_raise(input_str)
assert result == [1]


def test_parse_no_raise_integers():
input_str = "1,2,3"
result = cli.parse_no_raise(input_str)
assert result == [1, 2, 3]


def test_parse_no_raise_error_code():
input_str = "NO_COMMITIZEN_FOUND,NO_COMMITS_FOUND,NO_PATTERN_MAP"
result = cli.parse_no_raise(input_str)
assert result == [1, 3, 5]


def test_parse_no_raise_mix_integer_error_code():
input_str = "NO_COMMITIZEN_FOUND,2,NO_COMMITS_FOUND,4"
result = cli.parse_no_raise(input_str)
assert result == [1, 2, 3, 4]


def test_parse_no_raise_mix_invalid_arg_is_skipped():
input_str = "NO_COMMITIZEN_FOUND,2,nothing,4"
result = cli.parse_no_raise(input_str)
assert result == [1, 2, 4]

0 comments on commit 1570947

Please sign in to comment.