From 2b5c156559b23a26a7ad5e2378f2e97c9de2f765 Mon Sep 17 00:00:00 2001 From: crai0 Date: Fri, 15 Mar 2024 18:02:26 +0100 Subject: [PATCH 01/12] feat(commit): add retry_after_failure config option and --no-retry flag --- commitizen/cli.py | 6 ++++++ commitizen/commands/commit.py | 19 +++++++++++++++---- commitizen/defaults.py | 2 ++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index c25bd4f713..a442803d7f 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -123,6 +123,12 @@ def __call__( "action": "store_true", "help": "retry last commit", }, + { + "name": ["--no-retry"], + "action": "store_true", + "default": False, + "help": "skip retry if retry_after_failure is set to true", + }, { "name": "--dry-run", "action": "store_true", diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index b8e5eed6d4..390741afc1 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -33,13 +33,16 @@ def __init__(self, config: BaseConfig, arguments: dict): self.arguments = arguments self.temp_file: str = os.path.join( tempfile.gettempdir(), - "cz.commit{user}.backup".format(user=os.environ.get("USER", "")), + "cz.commit%{user}%{project_root}.backup".format( + user=os.environ.get("USER", ""), + project_root=str(git.find_git_project_root()).replace("/", "%"), + ), ) - def read_backup_message(self) -> str: + def read_backup_message(self) -> str | None: # Check the commit backup file exists if not os.path.isfile(self.temp_file): - raise NoCommitBackupError() + return None # Read commit message from backup with open(self.temp_file, encoding=self.encoding) as f: @@ -65,7 +68,7 @@ def prompt_commit_questions(self) -> str: def __call__(self): dry_run: bool = self.arguments.get("dry_run") - write_message_to_file = self.arguments.get("write_message_to_file") + write_message_to_file: bool = self.arguments.get("write_message_to_file") is_all: bool = self.arguments.get("all") if is_all: @@ -78,9 +81,17 @@ def __call__(self): raise NotAllowed(f"{write_message_to_file} is a directory") retry: bool = self.arguments.get("retry") + no_retry: bool = self.arguments.get("no_retry") + retry_after_failure: bool = self.config.settings.get("retry_after_failure") if retry: m = self.read_backup_message() + if m is None: + raise NoCommitBackupError() + elif retry_after_failure and not no_retry: + m = self.read_backup_message() + if m is None: + m = self.prompt_commit_questions() else: m = self.prompt_commit_questions() diff --git a/commitizen/defaults.py b/commitizen/defaults.py index 7aa2c793c5..071efd10b9 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -37,6 +37,7 @@ class Settings(TypedDict, total=False): version_type: str | None tag_format: str bump_message: str | None + retry_after_failure: bool allow_abort: bool allowed_prefixes: list[str] changelog_file: str @@ -77,6 +78,7 @@ class Settings(TypedDict, total=False): "version_scheme": None, "tag_format": "$version", # example v$version "bump_message": None, # bumped v$current_version to $new_version + "retry_after_failure": False, "allow_abort": False, "allowed_prefixes": [ "Merge", From 61aff14582d6730034f56757bbcf09d3f026fbe0 Mon Sep 17 00:00:00 2001 From: crai0 Date: Fri, 15 Mar 2024 18:50:41 +0100 Subject: [PATCH 02/12] test(commit): add tests for retry_after_failure config option and --no-retry flag --- tests/commands/test_commit_command.py | 63 +++++++++++++++++++++++++++ tests/test_conf.py | 2 + 2 files changed, 65 insertions(+) diff --git a/tests/commands/test_commit_command.py b/tests/commands/test_commit_command.py index e3f9989823..545defe0e4 100644 --- a/tests/commands/test_commit_command.py +++ b/tests/commands/test_commit_command.py @@ -94,6 +94,69 @@ def test_commit_retry_works(config, mocker: MockFixture): 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") +def test_commit_retry_after_failure_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("", "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) + + # Previous commit failed, so retry should pick up the backup commit + # 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() + 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") diff --git a/tests/test_conf.py b/tests/test_conf.py index dcac8e015c..a12bcdd35d 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -52,6 +52,7 @@ "version_scheme": None, "tag_format": "$version", "bump_message": None, + "retry_after_failure": False, "allow_abort": False, "allowed_prefixes": ["Merge", "Revert", "Pull request", "fixup!", "squash!"], "version_files": ["commitizen/__version__.py", "pyproject.toml"], @@ -80,6 +81,7 @@ "version_scheme": None, "tag_format": "$version", "bump_message": None, + "retry_after_failure": False, "allow_abort": False, "allowed_prefixes": ["Merge", "Revert", "Pull request", "fixup!", "squash!"], "version_files": ["commitizen/__version__.py", "pyproject.toml"], From 1b7a1ab1e63d6ad229c52178ec4872a502ba7d1a Mon Sep 17 00:00:00 2001 From: crai0 Date: Fri, 15 Mar 2024 19:02:20 +0100 Subject: [PATCH 03/12] refactor(utils): move backup path creation to utils --- commitizen/commands/commit.py | 9 ++------- commitizen/cz/utils.py | 13 +++++++++++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index 390741afc1..f2ccc6b1af 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -7,6 +7,7 @@ from commitizen import factory, git, out from commitizen.config import BaseConfig from commitizen.cz.exceptions import CzException +from commitizen.cz.utils import get_backup_file_path from commitizen.exceptions import ( CommitError, CustomError, @@ -31,13 +32,7 @@ def __init__(self, config: BaseConfig, arguments: dict): self.encoding = config.settings["encoding"] self.cz = factory.commiter_factory(self.config) self.arguments = arguments - self.temp_file: str = os.path.join( - tempfile.gettempdir(), - "cz.commit%{user}%{project_root}.backup".format( - user=os.environ.get("USER", ""), - project_root=str(git.find_git_project_root()).replace("/", "%"), - ), - ) + self.temp_file: str = get_backup_file_path() def read_backup_message(self) -> str | None: # Check the commit backup file exists diff --git a/commitizen/cz/utils.py b/commitizen/cz/utils.py index 71dac105a7..93c63a2213 100644 --- a/commitizen/cz/utils.py +++ b/commitizen/cz/utils.py @@ -1,6 +1,9 @@ import re +import os +import tempfile from commitizen.cz import exceptions +from commitizen import git def required_validator(answer, msg=None): @@ -15,3 +18,13 @@ def multiple_line_breaker(answer, sep="|"): def strip_local_version(version: str) -> str: return re.sub(r"\+.+", "", version) + + +def get_backup_file_path() -> str: + return os.path.join( + tempfile.gettempdir(), + "cz.commit%{user}%{project_root}.backup".format( + user=os.environ.get("USER", ""), + project_root=str(git.find_git_project_root()).replace("/", "%"), + ), + ) From 57262d5d53ccb800bc03f751be8754bbf21de569 Mon Sep 17 00:00:00 2001 From: crai0 Date: Fri, 15 Mar 2024 19:16:54 +0100 Subject: [PATCH 04/12] refactor(git-hooks): make git hooks use get_backup_file_path --- hooks/post-commit.py | 13 ++++++++----- hooks/prepare-commit-msg.py | 18 ++++++++---------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/hooks/post-commit.py b/hooks/post-commit.py index c2faebb738..a0ad5a7749 100755 --- a/hooks/post-commit.py +++ b/hooks/post-commit.py @@ -1,13 +1,16 @@ #!/usr/bin/env python -import os -import tempfile from pathlib import Path +try: + from commitizen.cz.utils import get_backup_file_path +except ImportError as error: + print("could not import commitizen:") + print(error) + exit(1) + def post_commit(): - backup_file = Path( - tempfile.gettempdir(), f"cz.commit{os.environ.get('USER', '')}.backup" - ) + backup_file = Path(get_backup_file_path()) # remove backup file if it exists if backup_file.is_file(): diff --git a/hooks/prepare-commit-msg.py b/hooks/prepare-commit-msg.py index 58beb3a0f8..d1ccf169cf 100755 --- a/hooks/prepare-commit-msg.py +++ b/hooks/prepare-commit-msg.py @@ -1,19 +1,19 @@ #!/usr/bin/env python -import os import shutil import subprocess import sys -import tempfile from pathlib import Path from subprocess import CalledProcessError +try: + from commitizen.cz.utils import get_backup_file_path +except ImportError as error: + print("could not import commitizen:") + print(error) + exit(1) -def prepare_commit_msg(commit_msg_file: Path) -> int: - # check that commitizen is installed - if shutil.which("cz") is None: - print("commitizen is not installed!") - return 0 +def prepare_commit_msg(commit_msg_file: Path) -> int: # check if the commit message needs to be generated using commitizen if ( subprocess.run( @@ -27,9 +27,7 @@ def prepare_commit_msg(commit_msg_file: Path) -> int: ).returncode != 0 ): - backup_file = Path( - tempfile.gettempdir(), f"cz.commit{os.environ.get('USER', '')}.backup" - ) + backup_file = Path(get_backup_file_path()) if backup_file.is_file(): # confirm if commit message from backup file should be reused From 261c4d71258a15c10d9aa8c6d33d78a255d66a32 Mon Sep 17 00:00:00 2001 From: crai0 Date: Fri, 15 Mar 2024 19:27:59 +0100 Subject: [PATCH 05/12] refactor(commit): remove unused tempfile import --- commitizen/commands/commit.py | 1 - 1 file changed, 1 deletion(-) diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index f2ccc6b1af..c9712a0fc7 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -1,6 +1,5 @@ import contextlib import os -import tempfile import questionary From 0f0668bbfd7f81012cee05a0a284e9ccae14ed18 Mon Sep 17 00:00:00 2001 From: crai0 Date: Fri, 15 Mar 2024 20:26:36 +0100 Subject: [PATCH 06/12] test(commit): add test for --no-retry flag --- tests/commands/test_commit_command.py | 48 +++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/commands/test_commit_command.py b/tests/commands/test_commit_command.py index 545defe0e4..f2f4f174c6 100644 --- a/tests/commands/test_commit_command.py +++ b/tests/commands/test_commit_command.py @@ -157,6 +157,54 @@ def test_commit_retry_after_failure_works(config, mocker: MockFixture): assert not os.path.isfile(temp_file) +@pytest.mark.usefixtures("staging_is_clean") +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("", "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) + + # provide different prompt to test that --no-retry ignore backup file + prompt_mock = mocker.patch("questionary.prompt") + prompt_mock.return_value = { + "prefix": "feat", + "subject": "user created", + "scope": "", + "is_breaking_change": False, + "body": "closes #22", + "footer": "", + } + + 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, {"no_retry": True})() + + commit_mock.assert_called_with("feat: user created\n\ncloses #22", args="") + prompt_mock.assert_called() + 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") From 96492fe70f33b0d9cd86943dde510c7540edbfe9 Mon Sep 17 00:00:00 2001 From: crai0 Date: Fri, 15 Mar 2024 20:50:01 +0100 Subject: [PATCH 07/12] docs: add retry_after_failure config and retry options for commit command --- docs/commit.md | 7 +++++++ docs/config.md | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/docs/commit.md b/docs/commit.md index 2215e0d805..54c792f743 100644 --- a/docs/commit.md +++ b/docs/commit.md @@ -29,3 +29,10 @@ For example, using the `-S` option on `git commit` to sign a commit is now commi !!! note Deprecation warning: A commit can be signed off using `cz commit --signoff` or the shortcut `cz commit -s`. This syntax is now deprecated in favor of the new `cz commit -- -s` syntax. + +### Retry + +You can use `cz commit --retry` to reuse the last commit message when the previous commit attempt failed. +To automatically retry when running `cz commit`, you can set the `retry_after_failure` +configuration option to `true`. Running `cz commit --no-retry` makes commitizen ignore `retry_after_failure`, forcing +a new commit message to be prompted. diff --git a/docs/config.md b/docs/config.md index 391c20f0fc..d6ab12abcd 100644 --- a/docs/config.md +++ b/docs/config.md @@ -82,6 +82,14 @@ Default: `None` Create custom commit message, useful to skip ci. [Read more][bump_message] +### `retry_after_failure` + +Type: `bool` + +Default: `false` + +Automatically retry failed commit when running `cz commit`. [Read more][retry_after_failure] + ### `allow_abort` Type: `bool` @@ -380,6 +388,7 @@ setup( [bump_message]: bump.md#bump_message [major-version-zero]: bump.md#-major-version-zero [prerelease-offset]: bump.md#-prerelease_offset +[retry_after_failure]: commit.md#retry [allow_abort]: check.md#allow-abort [version-scheme]: bump.md#version-scheme [pre_bump_hooks]: bump.md#pre_bump_hooks From dc11f8bc39d6edccf909353e8321f37b3c82b57b Mon Sep 17 00:00:00 2001 From: crai0 Date: Fri, 15 Mar 2024 21:17:18 +0100 Subject: [PATCH 08/12] refactor(commit): use Optional[str] instead of str | None --- commitizen/commands/commit.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index c9712a0fc7..2489abaf29 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -1,6 +1,8 @@ import contextlib import os +from typing import Optional + import questionary from commitizen import factory, git, out @@ -33,7 +35,7 @@ def __init__(self, config: BaseConfig, arguments: dict): self.arguments = arguments self.temp_file: str = get_backup_file_path() - def read_backup_message(self) -> str | None: + def read_backup_message(self) -> Optional[str]: # Check the commit backup file exists if not os.path.isfile(self.temp_file): return None From 9fa12c0d8b628e9f71191f4d6680e607c2c069de Mon Sep 17 00:00:00 2001 From: crai0 Date: Fri, 15 Mar 2024 21:34:22 +0100 Subject: [PATCH 09/12] refactor(utils): convert git project root to posix path for backup file name --- commitizen/cz/utils.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/commitizen/cz/utils.py b/commitizen/cz/utils.py index 93c63a2213..d5bd63c6fc 100644 --- a/commitizen/cz/utils.py +++ b/commitizen/cz/utils.py @@ -21,10 +21,17 @@ def strip_local_version(version: str) -> str: def get_backup_file_path() -> str: + project_root = git.find_git_project_root() + + if project_root is None: + project = "" + else: + project = project_root.as_posix().replace("/", "%") + return os.path.join( tempfile.gettempdir(), - "cz.commit%{user}%{project_root}.backup".format( + "cz.commit%{user}%{project}.backup".format( user=os.environ.get("USER", ""), - project_root=str(git.find_git_project_root()).replace("/", "%"), + project=project, ), ) From d545ff1c2196ca6b07cca00e20dc20c4b8beca90 Mon Sep 17 00:00:00 2001 From: crai0 Date: Fri, 15 Mar 2024 21:51:38 +0100 Subject: [PATCH 10/12] test(utils): add test for get_backup_file_path when git.find_project_root returns None --- tests/test_cz_utils.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_cz_utils.py b/tests/test_cz_utils.py index 94cc7f5b87..25c960c9a7 100644 --- a/tests/test_cz_utils.py +++ b/tests/test_cz_utils.py @@ -1,4 +1,5 @@ import pytest +from pytest_mock import MockFixture from commitizen.cz import exceptions, utils @@ -17,3 +18,9 @@ def test_multiple_line_breaker(): result = utils.multiple_line_breaker(message, "is") assert result == "th\n\nthe first line | and th\n\nthe second line" + + +def test_get_backup_file_path_no_project_root(mocker: MockFixture): + project_root_mock = mocker.patch("commitizen.git.find_git_project_root") + project_root_mock.return_value = None + assert utils.get_backup_file_path() From 506ca59eb809e48c42dc9d159434ae566850259d Mon Sep 17 00:00:00 2001 From: crai0 Date: Sat, 16 Mar 2024 19:48:54 +0100 Subject: [PATCH 11/12] test(commit): create new test for backup file creation and use fixture for other retry test cases --- tests/commands/test_commit_command.py | 112 ++++++++++---------------- 1 file changed, 42 insertions(+), 70 deletions(-) diff --git a/tests/commands/test_commit_command.py b/tests/commands/test_commit_command.py index f2f4f174c6..1930b2eaee 100644 --- a/tests/commands/test_commit_command.py +++ b/tests/commands/test_commit_command.py @@ -6,6 +6,7 @@ from commitizen import cmd, commands from commitizen.cz.exceptions import CzException +from commitizen.cz.utils import get_backup_file_path from commitizen.exceptions import ( CommitError, CustomError, @@ -25,6 +26,12 @@ def staging_is_clean(mocker: MockFixture, tmp_git_project): 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") @@ -46,18 +53,7 @@ def test_commit(config, mocker: MockFixture): @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") -def test_commit_retry_works(config, mocker: MockFixture): +def test_commit_backup_on_failure(config, mocker: MockFixture): prompt_mock = mocker.patch("questionary.prompt") prompt_mock.return_value = { "prefix": "feat", @@ -81,15 +77,32 @@ def test_commit_retry_works(config, mocker: MockFixture): error_mock.assert_called_once() assert os.path.isfile(temp_file) - # Previous commit failed, so retry should pick up the backup commit - # commit_mock = mocker.patch("commitizen.git.commit") + +@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") - commands.Commit(config, {"retry": True})() + commit_cmd = commands.Commit(config, {"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() + 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) @@ -118,46 +131,26 @@ def test_commit_retry_after_failure_no_backup(config, mocker: MockFixture): success_mock.assert_called_once() -@pytest.mark.usefixtures("staging_is_clean") +@pytest.mark.usefixtures("staging_is_clean", "backup_file") def test_commit_retry_after_failure_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("", "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) - - # Previous commit failed, so retry should pick up the backup commit - # 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_cmd = commands.Commit(config, {}) + 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() + 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") +@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 = { @@ -170,37 +163,16 @@ def test_commit_retry_after_failure_with_no_retry_works(config, mocker: MockFixt } 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) - - # provide different prompt to test that --no-retry ignore backup file - prompt_mock = mocker.patch("questionary.prompt") - prompt_mock.return_value = { - "prefix": "feat", - "subject": "user created", - "scope": "", - "is_breaking_change": False, - "body": "closes #22", - "footer": "", - } - 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, {"no_retry": 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 #22", args="") - prompt_mock.assert_called() + 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) From 888606bf89e6f857b5dbcf91814ad38b20b7a9f2 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Sat, 30 Mar 2024 15:22:30 +0800 Subject: [PATCH 12/12] style: refine coding style based on reviews --- commitizen/commands/commit.py | 5 +++-- commitizen/cz/utils.py | 9 ++------- hooks/post-commit.py | 3 +-- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index 2489abaf29..7591a28658 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -1,7 +1,8 @@ +from __future__ import annotations + import contextlib import os -from typing import Optional import questionary @@ -35,7 +36,7 @@ def __init__(self, config: BaseConfig, arguments: dict): self.arguments = arguments self.temp_file: str = get_backup_file_path() - def read_backup_message(self) -> Optional[str]: + def read_backup_message(self) -> str | None: # Check the commit backup file exists if not os.path.isfile(self.temp_file): return None diff --git a/commitizen/cz/utils.py b/commitizen/cz/utils.py index d5bd63c6fc..4df2edf39c 100644 --- a/commitizen/cz/utils.py +++ b/commitizen/cz/utils.py @@ -28,10 +28,5 @@ def get_backup_file_path() -> str: else: project = project_root.as_posix().replace("/", "%") - return os.path.join( - tempfile.gettempdir(), - "cz.commit%{user}%{project}.backup".format( - user=os.environ.get("USER", ""), - project=project, - ), - ) + user = os.environ.get("USER", "") + return os.path.join(tempfile.gettempdir(), f"cz.commit%{user}%{project}.backup") diff --git a/hooks/post-commit.py b/hooks/post-commit.py index a0ad5a7749..6444e5ca84 100755 --- a/hooks/post-commit.py +++ b/hooks/post-commit.py @@ -4,8 +4,7 @@ try: from commitizen.cz.utils import get_backup_file_path except ImportError as error: - print("could not import commitizen:") - print(error) + print(f"could not import commitizen:\n{error}") exit(1)