Skip to content

feat(check): Add --allow-abort option #512

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions commitizen/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,12 @@
"help": "commit message that needs to be checked",
"exclusive_group": "group1",
},
{
"name": ["--allow-abort"],
"action": "store_true",
"default": False,
"help": "allow empty commit messages, which typically abort a commit",
},
],
},
{
Expand Down
27 changes: 17 additions & 10 deletions commitizen/commands/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,26 @@ def __init__(self, config: BaseConfig, arguments: Dict[str, str], cwd=os.getcwd(
self.commit_msg_file: Optional[str] = arguments.get("commit_msg_file")
self.commit_msg: Optional[str] = arguments.get("message")
self.rev_range: Optional[str] = arguments.get("rev_range")
self.allow_abort: bool = bool(
arguments.get("allow_abort", config.settings["allow_abort"])
)

self._valid_command_argument()

self.config: BaseConfig = config
self.cz = factory.commiter_factory(self.config)

def _valid_command_argument(self):
number_args_provided = (
bool(self.commit_msg_file) + bool(self.commit_msg) + bool(self.rev_range)
num_exclusive_args_provided = sum(
arg is not None
for arg in (self.commit_msg_file, self.commit_msg, self.rev_range)
)
if number_args_provided == 0 and not os.isatty(0):
if num_exclusive_args_provided == 0 and not os.isatty(0):
self.commit_msg: Optional[str] = sys.stdin.read()
elif number_args_provided != 1:
elif num_exclusive_args_provided != 1:
raise InvalidCommandArgumentError(
(
"One and only one argument is required for check command! "
"Only one of --rev-range, --message, and --commit-msg-file is permitted by check command! "
"See 'cz check -h' for more information"
)
)
Expand All @@ -60,7 +64,7 @@ def __call__(self):
ill_formated_commits = [
commit
for commit in commits
if not Check.validate_commit_message(commit.message, pattern)
if not self.validate_commit_message(commit.message, pattern)
]
displayed_msgs_content = "\n".join(
[
Expand All @@ -79,15 +83,17 @@ def __call__(self):

def _get_commits(self):
# Get commit message from file (--commit-msg-file)
if self.commit_msg_file:
if self.commit_msg_file is not None:
# Enter this branch if commit_msg_file is "".
with open(self.commit_msg_file, "r", encoding="utf-8") as commit_file:
msg = commit_file.read()
msg = self._filter_comments(msg)
msg = msg.lstrip("\n")
commit_title = msg.split("\n")[0]
commit_body = "\n".join(msg.split("\n")[1:])
return [git.GitCommit(rev="", title=commit_title, body=commit_body)]
elif self.commit_msg:
elif self.commit_msg is not None:
# Enter this branch if commit_msg is "".
self.commit_msg = self._filter_comments(self.commit_msg)
return [git.GitCommit(rev="", title="", body=self.commit_msg)]

Expand All @@ -98,8 +104,9 @@ def _filter_comments(self, msg: str) -> str:
lines = [line for line in msg.split("\n") if not line.startswith("#")]
return "\n".join(lines)

@staticmethod
def validate_commit_message(commit_msg: str, pattern: str) -> bool:
def validate_commit_message(self, commit_msg: str, pattern: str) -> bool:
if not commit_msg:
return self.allow_abort
if (
commit_msg.startswith("Merge")
or commit_msg.startswith("Revert")
Expand Down
2 changes: 1 addition & 1 deletion commitizen/cz/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def discover_plugins(path: Iterable[str] = None) -> Dict[str, Type[BaseCommitize
Dict[str, Type[BaseCommitizen]]: Registry with found plugins
"""
plugins = {}
for finder, name, ispkg in pkgutil.iter_modules(path):
for _finder, name, _ispkg in pkgutil.iter_modules(path):
try:
if name.startswith("cz_"):
plugins[name] = importlib.import_module(name).discover_this
Expand Down
2 changes: 2 additions & 0 deletions commitizen/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class Settings(TypedDict, total=False):
version_files: List[str]
tag_format: Optional[str]
bump_message: Optional[str]
allow_abort: bool
changelog_file: str
changelog_incremental: bool
changelog_start_rev: Optional[str]
Expand All @@ -56,6 +57,7 @@ class Settings(TypedDict, total=False):
"version_files": [],
"tag_format": None, # example v$version
"bump_message": None, # bumped v$current_version to $new_version
"allow_abort": False,
"changelog_file": "CHANGELOG.md",
"changelog_incremental": False,
"changelog_start_rev": None,
Expand Down
15 changes: 14 additions & 1 deletion docs/check.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ If you want to setup an automatic check before every git commit, please refer to
[Automatically check message before commit](auto_check.md).

## Usage
There are three arguments that you can use one of them to check commit message.
There are three mutually exclusive ways to use `cz check`:

- with `--rev-range` to check a range of pre-existing commits
- with `--message` or by piping the message to it to check a given string
- or with `--commit-msg-file` to read the commit message from a file

### Git Rev Range
If you'd like to check a commit's message after it has already been created, then you can specify the range of commits to check with `--rev-range REV_RANGE`.
Expand Down Expand Up @@ -46,3 +50,12 @@ $ cz check --commit-msg-file COMMIT_MSG_FILE

In this option, COMMIT_MSG_FILE is the path of the temporal file that contains the commit message.
This argument can be useful when cooperating with git hook, please check [Automatically check message before commit](auto_check.md) for more information about how to use this argument with git hook.

### Allow Abort

```bash
cz check --message MESSAGE --allow-abort
```

Empty commit messages typically instruct Git to abort a commit, so you can pass `--allow-abort` to
permit them. Since `git commit` accepts an `--allow-empty-message` flag (primarily for wrapper scripts), you may wish to disallow such commits in CI. `--allow-abort` may be used in conjunction with any of the other options.
2 changes: 2 additions & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ commitizen:
| `update_changelog_on_bump` | `bool` | `false` | Create changelog when running `cz bump` |
| `annotated_tag` | `bool` | `false` | Use annotated tags instead of lightweight tags. [See difference][annotated-tags-vs-lightweight] |
| `bump_message` | `str` | `None` | Create custom commit message, useful to skip ci. [See more][bump_message] |
| `allow_abort` | `bool` | `false` | Disallow empty commit messages, useful in ci. [See more][allow_abort] |
| `changelog_file` | `str` | `CHANGELOG.md` | filename of exported changelog |
| `changelog_incremental` | `bool` | `false` | Update changelog with the missing versions. This is good if you don't want to replace previous versions in the file. Note: when doing `cz bump --changelog` this is automatically set to `true` |
| `changelog_start_rev` | `str` | `None` | Start from a given git rev to generate the changelog |
Expand All @@ -141,6 +142,7 @@ commitizen:
[version_files]: bump.md#version_files
[tag_format]: bump.md#tag_format
[bump_message]: bump.md#bump_message
[allow_abort]: check.md#allow-abort
[additional-features]: https://github.com/tmbo/questionary#additional-features
[customization]: customization.md
[shortcuts]: customization.md#shortcut-keys
Expand Down
47 changes: 44 additions & 3 deletions tests/commands/test_check_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,15 @@ def test_check_a_range_of_git_commits_and_failed(config, mocker):
error_mock.assert_called_once()


def test_check_command_with_invalid_argment(config):
def test_check_command_with_invalid_argument(config):
with pytest.raises(InvalidCommandArgumentError) as excinfo:
commands.Check(
config=config,
arguments={"commit_msg_file": "some_file", "rev_range": "HEAD~10..master"},
)
assert "One and only one argument is required for check command!" in str(
excinfo.value
assert (
"Only one of --rev-range, --message, and --commit-msg-file is permitted by check command!"
in str(excinfo.value)
)


Expand Down Expand Up @@ -257,6 +258,46 @@ def test_check_command_with_invalid_message(config, mocker):
error_mock.assert_called_once()


def test_check_command_with_empty_message(config, mocker):
error_mock = mocker.patch("commitizen.out.error")
check_cmd = commands.Check(config=config, arguments={"message": ""})

with pytest.raises(InvalidCommitMessageError):
check_cmd()
error_mock.assert_called_once()


def test_check_command_with_allow_abort_arg(config, mocker):
success_mock = mocker.patch("commitizen.out.success")
check_cmd = commands.Check(
config=config, arguments={"message": "", "allow_abort": True}
)

check_cmd()
success_mock.assert_called_once()


def test_check_command_with_allow_abort_config(config, mocker):
success_mock = mocker.patch("commitizen.out.success")
config.settings["allow_abort"] = True
check_cmd = commands.Check(config=config, arguments={"message": ""})

check_cmd()
success_mock.assert_called_once()


def test_check_command_override_allow_abort_config(config, mocker):
error_mock = mocker.patch("commitizen.out.error")
config.settings["allow_abort"] = True
check_cmd = commands.Check(
config=config, arguments={"message": "", "allow_abort": False}
)

with pytest.raises(InvalidCommitMessageError):
check_cmd()
error_mock.assert_called_once()


def test_check_command_with_pipe_message(mocker, capsys):
testargs = ["cz", "check"]
mocker.patch.object(sys, "argv", testargs)
Expand Down
2 changes: 2 additions & 0 deletions tests/test_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"version": "1.0.0",
"tag_format": None,
"bump_message": None,
"allow_abort": False,
"version_files": ["commitizen/__version__.py", "pyproject.toml"],
"style": [["pointer", "reverse"], ["question", "underline"]],
"changelog_file": "CHANGELOG.md",
Expand All @@ -54,6 +55,7 @@
"version": "2.0.0",
"tag_format": None,
"bump_message": None,
"allow_abort": False,
"version_files": ["commitizen/__version__.py", "pyproject.toml"],
"style": [["pointer", "reverse"], ["question", "underline"]],
"changelog_file": "CHANGELOG.md",
Expand Down