Adding upstream version 4.6.0+dfsg.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
f3ad83a1a5
commit
167a3f8553
275 changed files with 30423 additions and 0 deletions
527
tests/commands/test_commit_command.py
Normal file
527
tests/commands/test_commit_command.py
Normal file
|
@ -0,0 +1,527 @@
|
|||
import os
|
||||
import sys
|
||||
from unittest.mock import ANY
|
||||
|
||||
import pytest
|
||||
from pytest_mock import MockFixture
|
||||
|
||||
from commitizen import cli, cmd, commands
|
||||
from commitizen.cz.exceptions import CzException
|
||||
from commitizen.cz.utils import get_backup_file_path
|
||||
from commitizen.exceptions import (
|
||||
CommitError,
|
||||
CommitMessageLengthExceededError,
|
||||
CustomError,
|
||||
DryRunExit,
|
||||
NoAnswersError,
|
||||
NoCommitBackupError,
|
||||
NotAGitProjectError,
|
||||
NotAllowed,
|
||||
NothingToCommitError,
|
||||
)
|
||||
from tests.utils import skip_below_py_3_13
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def staging_is_clean(mocker: MockFixture, tmp_git_project):
|
||||
is_staging_clean_mock = mocker.patch("commitizen.git.is_staging_clean")
|
||||
is_staging_clean_mock.return_value = False
|
||||
return tmp_git_project
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def backup_file(tmp_git_project):
|
||||
with open(get_backup_file_path(), "w") as backup_file:
|
||||
backup_file.write("backup commit")
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
commands.Commit(config, {})()
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_backup_on_failure(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "closes #21",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("", "error", b"", b"", 9)
|
||||
error_mock = mocker.patch("commitizen.out.error")
|
||||
|
||||
with pytest.raises(CommitError):
|
||||
commit_cmd = commands.Commit(config, {})
|
||||
temp_file = commit_cmd.temp_file
|
||||
commit_cmd()
|
||||
|
||||
prompt_mock.assert_called_once()
|
||||
error_mock.assert_called_once()
|
||||
assert os.path.isfile(temp_file)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_retry_fails_no_backup(config, mocker: MockFixture):
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
|
||||
with pytest.raises(NoCommitBackupError) as excinfo:
|
||||
commands.Commit(config, {"retry": True})()
|
||||
|
||||
assert NoCommitBackupError.message in str(excinfo.value)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean", "backup_file")
|
||||
def test_commit_retry_works(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
commit_cmd = commands.Commit(config, {"retry": True})
|
||||
temp_file = commit_cmd.temp_file
|
||||
commit_cmd()
|
||||
|
||||
commit_mock.assert_called_with("backup commit", args="")
|
||||
prompt_mock.assert_not_called()
|
||||
success_mock.assert_called_once()
|
||||
assert not os.path.isfile(temp_file)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_retry_after_failure_no_backup(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "closes #21",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
config.settings["retry_after_failure"] = True
|
||||
commands.Commit(config, {})()
|
||||
|
||||
commit_mock.assert_called_with("feat: user created\n\ncloses #21", args="")
|
||||
prompt_mock.assert_called_once()
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean", "backup_file")
|
||||
def test_commit_retry_after_failure_works(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
config.settings["retry_after_failure"] = True
|
||||
commit_cmd = commands.Commit(config, {})
|
||||
temp_file = commit_cmd.temp_file
|
||||
commit_cmd()
|
||||
|
||||
commit_mock.assert_called_with("backup commit", args="")
|
||||
prompt_mock.assert_not_called()
|
||||
success_mock.assert_called_once()
|
||||
assert not os.path.isfile(temp_file)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean", "backup_file")
|
||||
def test_commit_retry_after_failure_with_no_retry_works(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "closes #21",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
config.settings["retry_after_failure"] = True
|
||||
commit_cmd = commands.Commit(config, {"no_retry": True})
|
||||
temp_file = commit_cmd.temp_file
|
||||
commit_cmd()
|
||||
|
||||
commit_mock.assert_called_with("feat: user created\n\ncloses #21", args="")
|
||||
prompt_mock.assert_called_once()
|
||||
success_mock.assert_called_once()
|
||||
assert not os.path.isfile(temp_file)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_command_with_dry_run_option(config, mocker: MockFixture):
|
||||
prompt_mock = mocker = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "closes #57",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
with pytest.raises(DryRunExit):
|
||||
commit_cmd = commands.Commit(config, {"dry_run": True})
|
||||
commit_cmd()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_command_with_write_message_to_file_option(
|
||||
config, tmp_path, mocker: MockFixture
|
||||
):
|
||||
tmp_file = tmp_path / "message"
|
||||
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
commands.Commit(config, {"write_message_to_file": tmp_file})()
|
||||
success_mock.assert_called_once()
|
||||
assert tmp_file.exists()
|
||||
assert tmp_file.read_text() == "feat: user created"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_command_with_invalid_write_message_to_file_option(
|
||||
config, tmp_path, mocker: MockFixture
|
||||
):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
with pytest.raises(NotAllowed):
|
||||
commit_cmd = commands.Commit(config, {"write_message_to_file": tmp_path})
|
||||
commit_cmd()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_command_with_signoff_option(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
commands.Commit(config, {"signoff": True})()
|
||||
|
||||
commit_mock.assert_called_once_with(ANY, args="-s")
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_command_with_always_signoff_enabled(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
config.settings["always_signoff"] = True
|
||||
commands.Commit(config, {})()
|
||||
|
||||
commit_mock.assert_called_once_with(ANY, args="-s")
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_command_with_gpgsign_and_always_signoff_enabled(
|
||||
config, mocker: MockFixture
|
||||
):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
config.settings["always_signoff"] = True
|
||||
commands.Commit(config, {"extra_cli_args": "-S"})()
|
||||
|
||||
commit_mock.assert_called_once_with(ANY, args="-S -s")
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("tmp_git_project")
|
||||
def test_commit_when_nothing_to_commit(config, mocker: MockFixture):
|
||||
is_staging_clean_mock = mocker.patch("commitizen.git.is_staging_clean")
|
||||
is_staging_clean_mock.return_value = True
|
||||
|
||||
with pytest.raises(NothingToCommitError) as excinfo:
|
||||
commit_cmd = commands.Commit(config, {})
|
||||
commit_cmd()
|
||||
|
||||
assert "No files added to staging!" in str(excinfo.value)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_with_allow_empty(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "closes #21",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
commands.Commit(config, {"extra_cli_args": "--allow-empty"})()
|
||||
|
||||
commit_mock.assert_called_with(
|
||||
"feat: user created\n\ncloses #21", args="--allow-empty"
|
||||
)
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_with_signoff_and_allow_empty(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "closes #21",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
config.settings["always_signoff"] = True
|
||||
commands.Commit(config, {"extra_cli_args": "--allow-empty"})()
|
||||
|
||||
commit_mock.assert_called_with(
|
||||
"feat: user created\n\ncloses #21", args="--allow-empty -s"
|
||||
)
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_when_customized_expected_raised(config, mocker: MockFixture, capsys):
|
||||
_err = ValueError()
|
||||
_err.__context__ = CzException("This is the root custom err")
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.side_effect = _err
|
||||
|
||||
with pytest.raises(CustomError) as excinfo:
|
||||
commit_cmd = commands.Commit(config, {})
|
||||
commit_cmd()
|
||||
|
||||
# Assert only the content in the formatted text
|
||||
assert "This is the root custom err" in str(excinfo.value)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_when_non_customized_expected_raised(
|
||||
config, mocker: MockFixture, capsys
|
||||
):
|
||||
_err = ValueError()
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.side_effect = _err
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
commit_cmd = commands.Commit(config, {})
|
||||
commit_cmd()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_when_no_user_answer(config, mocker: MockFixture, capsys):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = None
|
||||
|
||||
with pytest.raises(NoAnswersError):
|
||||
commit_cmd = commands.Commit(config, {})
|
||||
commit_cmd()
|
||||
|
||||
|
||||
def test_commit_in_non_git_project(tmpdir, config):
|
||||
with tmpdir.as_cwd():
|
||||
with pytest.raises(NotAGitProjectError):
|
||||
commands.Commit(config, {})
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_command_with_all_option(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
add_mock = mocker.patch("commitizen.git.add")
|
||||
commands.Commit(config, {"all": True})()
|
||||
add_mock.assert_called()
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_command_with_extra_args(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prompt_mock.return_value = {
|
||||
"prefix": "feat",
|
||||
"subject": "user created",
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "",
|
||||
"footer": "",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
commands.Commit(config, {"extra_cli_args": "-- -extra-args1 -extra-arg2"})()
|
||||
commit_mock.assert_called_once_with(ANY, args="-- -extra-args1 -extra-arg2")
|
||||
success_mock.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
def test_commit_command_with_message_length_limit(config, mocker: MockFixture):
|
||||
prompt_mock = mocker.patch("questionary.prompt")
|
||||
prefix = "feat"
|
||||
subject = "random subject"
|
||||
message_length = len(prefix) + len(": ") + len(subject)
|
||||
prompt_mock.return_value = {
|
||||
"prefix": prefix,
|
||||
"subject": subject,
|
||||
"scope": "",
|
||||
"is_breaking_change": False,
|
||||
"body": "random body",
|
||||
"footer": "random footer",
|
||||
}
|
||||
|
||||
commit_mock = mocker.patch("commitizen.git.commit")
|
||||
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
|
||||
success_mock = mocker.patch("commitizen.out.success")
|
||||
|
||||
commands.Commit(config, {"message_length_limit": message_length})()
|
||||
success_mock.assert_called_once()
|
||||
|
||||
with pytest.raises(CommitMessageLengthExceededError):
|
||||
commands.Commit(config, {"message_length_limit": message_length - 1})()
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("staging_is_clean")
|
||||
@pytest.mark.parametrize("editor", ["vim", None])
|
||||
def test_manual_edit(editor, config, mocker: MockFixture, tmp_path):
|
||||
mocker.patch("commitizen.git.get_core_editor", return_value=editor)
|
||||
subprocess_mock = mocker.patch("subprocess.call")
|
||||
|
||||
mocker.patch("shutil.which", return_value=editor)
|
||||
|
||||
test_message = "Initial commit message"
|
||||
temp_file = tmp_path / "temp_commit_message"
|
||||
temp_file.write_text(test_message)
|
||||
|
||||
mock_temp_file = mocker.patch("tempfile.NamedTemporaryFile")
|
||||
mock_temp_file.return_value.__enter__.return_value.name = str(temp_file)
|
||||
|
||||
commit_cmd = commands.Commit(config, {"edit": True})
|
||||
|
||||
if editor is None:
|
||||
with pytest.raises(RuntimeError):
|
||||
commit_cmd.manual_edit(test_message)
|
||||
else:
|
||||
edited_message = commit_cmd.manual_edit(test_message)
|
||||
|
||||
subprocess_mock.assert_called_once_with(["vim", str(temp_file)])
|
||||
|
||||
assert edited_message == test_message.strip()
|
||||
|
||||
temp_file.unlink()
|
||||
|
||||
|
||||
@skip_below_py_3_13
|
||||
def test_commit_command_shows_description_when_use_help_option(
|
||||
mocker: MockFixture, capsys, file_regression
|
||||
):
|
||||
testargs = ["cz", "commit", "--help"]
|
||||
mocker.patch.object(sys, "argv", testargs)
|
||||
with pytest.raises(SystemExit):
|
||||
cli.main()
|
||||
|
||||
out, _ = capsys.readouterr()
|
||||
file_regression.check(out, extension=".txt")
|
Loading…
Add table
Add a link
Reference in a new issue