Skip to content

Commit 556f71a

Browse files
authored
Merge pull request #41 from Woile/feature/40-retry-functionality
feat(commit): new retry argument to execute previous commit again
2 parents 54f9d62 + d39b131 commit 556f71a

File tree

5 files changed

+100
-12
lines changed

5 files changed

+100
-12
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# CHANGELOG
22

3+
## Unreleased
4+
5+
### Feature
6+
7+
- new retry argument to execute previous commit again
8+
39
## v1.5.1
410

511
### Fix

commitizen/cli.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@
4141
"name": ["commit", "c"],
4242
"help": "create new commit",
4343
"func": commands.Commit,
44+
"arguments": [
45+
{
46+
"name": ["--retry"],
47+
"action": "store_true",
48+
"help": "retry last commit",
49+
},
50+
]
4451
},
4552
{
4653
"name": "example",

commitizen/commands/commit.py

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,64 @@
1+
import contextlib
2+
import os
13
import questionary
4+
import tempfile
5+
26
from commitizen import factory, out, git
37

48

59
NO_ANSWERS = 5
610
COMMIT_ERROR = 6
11+
NO_COMMIT_BACKUP = 7
712

813

914
class Commit:
1015
"""Show prompt for the user to create a guided commit."""
1116

12-
def __init__(self, config: dict, *args):
17+
def __init__(self, config: dict, arguments: dict):
1318
self.config: dict = config
1419
self.cz = factory.commiter_factory(self.config)
20+
self.arguments = arguments
21+
self.temp_file: str = os.path.join(tempfile.gettempdir(), "cz.commit.backup")
1522

1623
def __call__(self):
17-
cz = self.cz
18-
questions = cz.questions()
19-
answers = questionary.prompt(questions)
20-
if not answers:
21-
raise SystemExit(NO_ANSWERS)
22-
m = cz.message(answers)
24+
retry: bool = self.arguments.get("retry")
25+
26+
if retry:
27+
# Check the commit backup file exists
28+
if not os.path.isfile(self.temp_file):
29+
out.error("No commit backup found")
30+
raise SystemExit(NO_COMMIT_BACKUP)
31+
32+
# Read commit message from backup
33+
with open(self.temp_file, "r") as f:
34+
m = f.read().strip()
35+
else:
36+
# Prompt user for the commit message
37+
cz = self.cz
38+
questions = cz.questions()
39+
answers = questionary.prompt(questions)
40+
if not answers:
41+
raise SystemExit(NO_ANSWERS)
42+
m = cz.message(answers)
43+
2344
out.info(f"\n{m}\n")
2445
c = git.commit(m)
2546

2647
if c.err:
2748
out.error(c.err)
49+
50+
# Create commit backup
51+
with open(self.temp_file, "w") as f:
52+
f.write(m)
53+
2854
raise SystemExit(COMMIT_ERROR)
2955

3056
if "nothing added" in c.out or "no changes added to commit" in c.out:
3157
out.error(c.out)
3258
elif c.err:
3359
out.error(c.err)
3460
else:
61+
with contextlib.suppress(FileNotFoundError):
62+
os.remove(self.temp_file)
3563
out.write(c.out)
3664
out.success("Commit successful!")

tests/test_cli.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ def test_sysexit_no_argv():
1010

1111
def test_ls(mocker, capsys):
1212
testargs = ["cz", "-n", "cz_jira", "ls"]
13-
mocker.patch.object(sys, 'argv', testargs)
13+
mocker.patch.object(sys, "argv", testargs)
1414
cli.main()
1515
out, err = capsys.readouterr()
1616

@@ -21,5 +21,5 @@ def test_ls(mocker, capsys):
2121
def test_version(mocker):
2222
testargs = ["cz", "--version"]
2323
with pytest.raises(SystemExit):
24-
mocker.patch.object(sys, 'argv', testargs)
25-
cli.main()
24+
mocker.patch.object(sys, "argv", testargs)
25+
cli.main()

tests/test_commands.py

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
# import pytest
1+
import os
2+
import pytest
23
from unittest import mock
4+
35
from commitizen import defaults, commands, cmd
46

57
config = {"name": defaults.name}
@@ -20,8 +22,53 @@ def test_commit(mocker):
2022
commit_mock.return_value = cmd.Command("success", "", "", "")
2123
success_mock = mocker.patch("commitizen.out.success")
2224

23-
commands.Commit(config)()
25+
commands.Commit(config, {})()
26+
success_mock.assert_called_once()
27+
28+
29+
def test_commit_retry_fails_no_backup(mocker):
30+
commit_mock = mocker.patch("commitizen.git.commit")
31+
commit_mock.return_value = cmd.Command("success", "", "", "")
32+
33+
with pytest.raises(SystemExit):
34+
commands.Commit(config, {"retry": True})()
35+
36+
37+
def test_commit_retry_works(mocker):
38+
prompt_mock = mocker.patch("questionary.prompt")
39+
prompt_mock.return_value = {
40+
"prefix": "feat",
41+
"subject": "user created",
42+
"scope": "",
43+
"is_breaking_change": False,
44+
"body": "closes #21",
45+
"footer": "",
46+
}
47+
48+
commit_mock = mocker.patch("commitizen.git.commit")
49+
commit_mock.return_value = cmd.Command("", "error", "", "")
50+
error_mock = mocker.patch("commitizen.out.error")
51+
52+
with pytest.raises(SystemExit):
53+
commit_cmd = commands.Commit(config, {})
54+
temp_file = commit_cmd.temp_file
55+
commit_cmd()
56+
57+
prompt_mock.assert_called_once()
58+
error_mock.assert_called_once()
59+
assert os.path.isfile(temp_file)
60+
61+
# Previous commit failed, so retry should pick up the backup commit
62+
# commit_mock = mocker.patch("commitizen.git.commit")
63+
commit_mock.return_value = cmd.Command("success", "", "", "")
64+
success_mock = mocker.patch("commitizen.out.success")
65+
66+
commands.Commit(config, {"retry": True})()
67+
68+
commit_mock.assert_called_with("feat: user created\n\ncloses #21")
69+
prompt_mock.assert_called_once()
2470
success_mock.assert_called_once()
71+
assert not os.path.isfile(temp_file)
2572

2673

2774
def test_example():

0 commit comments

Comments
 (0)