Skip to content

Commit a472bea

Browse files
bearomorphismLee-W
authored andcommitted
fix(Init): raise InitFailedError on keyboard interrupt on pre-commit hook question, simplify logic, remove unreachable code path
1 parent 279c420 commit a472bea

File tree

2 files changed

+37
-74
lines changed

2 files changed

+37
-74
lines changed

commitizen/commands/init.py

Lines changed: 34 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,43 @@ def __call__(self) -> None:
150150
tag_format = self._ask_tag_format(tag) # confirm & text
151151
update_changelog_on_bump = self._ask_update_changelog_on_bump() # confirm
152152
major_version_zero = self._ask_major_version_zero(version) # confirm
153+
hook_types: list[str] | None = questionary.checkbox(
154+
"What types of pre-commit hook you want to install? (Leave blank if you don't want to install)",
155+
choices=[
156+
questionary.Choice("commit-msg", checked=False),
157+
questionary.Choice("pre-push", checked=False),
158+
],
159+
).unsafe_ask()
153160
except KeyboardInterrupt:
154161
raise InitFailedError("Stopped by user")
155162

163+
if hook_types:
164+
config_data = self._get_config_data()
165+
with smart_open(
166+
self._PRE_COMMIT_CONFIG_PATH, "w", encoding=self.encoding
167+
) as config_file:
168+
yaml.safe_dump(config_data, stream=config_file)
169+
170+
if not self.project_info.is_pre_commit_installed:
171+
raise InitFailedError(
172+
"Failed to install pre-commit hook.\n"
173+
"pre-commit is not installed in current environment."
174+
)
175+
176+
cmd_str = "pre-commit install " + " ".join(
177+
f"--hook-type {ty}" for ty in hook_types
178+
)
179+
c = cmd.run(cmd_str)
180+
if c.return_code != 0:
181+
raise InitFailedError(
182+
"Failed to install pre-commit hook.\n"
183+
f"Error running {cmd_str}."
184+
"Outputs are attached below:\n"
185+
f"stdout: {c.out}\n"
186+
f"stderr: {c.err}"
187+
)
188+
out.write("commitizen pre-commit hook is now installed in your '.git'\n")
189+
156190
# Initialize configuration
157191
if "toml" in config_path:
158192
self.config = TomlConfig(data="", path=config_path)
@@ -161,20 +195,6 @@ def __call__(self) -> None:
161195
elif "yaml" in config_path:
162196
self.config = YAMLConfig(data="", path=config_path)
163197

164-
# Collect hook data
165-
hook_types = questionary.checkbox(
166-
"What types of pre-commit hook you want to install? (Leave blank if you don't want to install)",
167-
choices=[
168-
questionary.Choice("commit-msg", checked=False),
169-
questionary.Choice("pre-push", checked=False),
170-
],
171-
).unsafe_ask()
172-
if hook_types:
173-
try:
174-
self._install_pre_commit_hook(hook_types)
175-
except InitFailedError as e:
176-
raise InitFailedError(f"Failed to install pre-commit hook.\n{e}")
177-
178198
# Create and initialize config
179199
self.config.init_empty_config_content()
180200

@@ -321,26 +341,6 @@ def _ask_update_changelog_on_bump(self) -> bool:
321341
).unsafe_ask()
322342
return update_changelog_on_bump
323343

324-
def _exec_install_pre_commit_hook(self, hook_types: list[str]) -> None:
325-
cmd_str = self._gen_pre_commit_cmd(hook_types)
326-
c = cmd.run(cmd_str)
327-
if c.return_code != 0:
328-
err_msg = (
329-
f"Error running {cmd_str}."
330-
"Outputs are attached below:\n"
331-
f"stdout: {c.out}\n"
332-
f"stderr: {c.err}"
333-
)
334-
raise InitFailedError(err_msg)
335-
336-
def _gen_pre_commit_cmd(self, hook_types: list[str]) -> str:
337-
"""Generate pre-commit command according to given hook types"""
338-
if not hook_types:
339-
raise ValueError("At least 1 hook type should be provided.")
340-
return "pre-commit install " + " ".join(
341-
f"--hook-type {ty}" for ty in hook_types
342-
)
343-
344344
def _get_config_data(self) -> dict[str, Any]:
345345
CZ_HOOK_CONFIG = {
346346
"repo": "https://github.com/commitizen-tools/commitizen",
@@ -369,17 +369,3 @@ def _get_config_data(self) -> dict[str, Any]:
369369
else:
370370
repos.append(CZ_HOOK_CONFIG)
371371
return config_data
372-
373-
def _install_pre_commit_hook(self, hook_types: list[str] | None = None) -> None:
374-
config_data = self._get_config_data()
375-
with smart_open(
376-
self._PRE_COMMIT_CONFIG_PATH, "w", encoding=self.encoding
377-
) as config_file:
378-
yaml.safe_dump(config_data, stream=config_file)
379-
380-
if not self.project_info.is_pre_commit_installed:
381-
raise InitFailedError("pre-commit is not installed in current environment.")
382-
if hook_types is None:
383-
hook_types = ["commit-msg", "pre-push"]
384-
self._exec_install_pre_commit_hook(hook_types)
385-
out.write("commitizen pre-commit hook is now installed in your '.git'\n")

tests/commands/test_init_command.py

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import yaml
1010
from pytest_mock import MockFixture
1111

12-
from commitizen import cli, commands
12+
from commitizen import cli, cmd, commands
1313
from commitizen.__version__ import __version__
1414
from commitizen.config.base_config import BaseConfig
1515
from commitizen.exceptions import InitFailedError, NoAnswersError
@@ -117,12 +117,6 @@ def test_init_without_choosing_tag(config: BaseConfig, mocker: MockFixture, tmpd
117117
commands.Init(config)()
118118

119119

120-
def test_executed_pre_commit_command(config: BaseConfig):
121-
init = commands.Init(config)
122-
expected_cmd = "pre-commit install --hook-type commit-msg --hook-type pre-push"
123-
assert init._gen_pre_commit_cmd(["commit-msg", "pre-push"]) == expected_cmd
124-
125-
126120
@pytest.fixture(scope="function")
127121
def pre_commit_installed(mocker: MockFixture):
128122
# Assume the `pre-commit` is installed
@@ -132,8 +126,8 @@ def pre_commit_installed(mocker: MockFixture):
132126
)
133127
# And installation success (i.e. no exception raised)
134128
mocker.patch(
135-
"commitizen.commands.init.Init._exec_install_pre_commit_hook",
136-
return_value=None,
129+
"commitizen.cmd.run",
130+
return_value=cmd.Command("0.0.1", "", b"", b"", 0),
137131
)
138132

139133

@@ -244,23 +238,6 @@ def test_pre_commit_not_installed(
244238
with pytest.raises(InitFailedError):
245239
commands.Init(config)()
246240

247-
def test_pre_commit_exec_failed(
248-
_, mocker: MockFixture, config: BaseConfig, default_choice: str, tmpdir
249-
):
250-
# Assume `pre-commit` is installed
251-
mocker.patch(
252-
"commitizen.commands.init.ProjectInfo.is_pre_commit_installed",
253-
return_value=True,
254-
)
255-
# But pre-commit installation will fail
256-
mocker.patch(
257-
"commitizen.commands.init.Init._exec_install_pre_commit_hook",
258-
side_effect=InitFailedError("Mock init failed error."),
259-
)
260-
with tmpdir.as_cwd():
261-
with pytest.raises(InitFailedError):
262-
commands.Init(config)()
263-
264241

265242
class TestAskTagFormat:
266243
def test_confirm_v_tag_format(self, mocker: MockFixture, config: BaseConfig):

0 commit comments

Comments
 (0)