Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 86c4f60

Browse files
BogayLee-W
authored andcommitted
feat(init): allow user to select which type of pre commit hooks to install
See more: https://commitizen-tools.github.io/commitizen/#integrating-with-pre-commit
1 parent f1b581c commit 86c4f60

File tree

2 files changed

+69
-73
lines changed

2 files changed

+69
-73
lines changed

‎commitizen/commands/init.py‎

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import os
22
import shutil
3-
from typing import Any, Dict
3+
from typing import Any, Dict, List, Optional
44

55
import questionary
66
import yaml
@@ -42,8 +42,15 @@ def __call__(self):
4242
values_to_add["tag_format"] = self._ask_tag_format(tag)
4343
self._update_config_file(values_to_add)
4444

45-
if questionary.confirm("Do you want to install pre-commit hook?").ask():
46-
if not self._install_pre_commit_hook():
45+
hook_types = questionary.checkbox(
46+
"What types of pre-commit hook you want to install? (Leave blank if you don't want to install)",
47+
choices=[
48+
questionary.Choice("commit-msg", checked=True),
49+
questionary.Choice("pre-push", checked=True),
50+
],
51+
).ask()
52+
if hook_types:
53+
if not self._install_pre_commit_hook(hook_types):
4754
raise InitFailedError(
4855
"Installation failed. See error outputs for more information."
4956
)
@@ -116,8 +123,12 @@ def _ask_tag_format(self, latest_tag) -> str:
116123
def _search_pre_commit(self):
117124
return shutil.which("pre-commit") is not None
118125

119-
def _exec_install_pre_commit_hook(self):
120-
cmd_str = "pre-commit install --hook-type commit-msg"
126+
def _exec_install_pre_commit_hook(self, hook_types: List[str]):
127+
if not hook_types:
128+
raise ValueError("At least 1 hook type should be provided.")
129+
cmd_str = "pre-commit install " + "".join(
130+
f"--hook-type {ty}" for ty in hook_types
131+
)
121132
c = cmd.run(cmd_str)
122133
if c.return_code != 0:
123134
out.error(f"Error running {cmd_str}. Outputs are attached below:")
@@ -126,12 +137,15 @@ def _exec_install_pre_commit_hook(self):
126137
return False
127138
return True
128139

129-
def _install_pre_commit_hook(self) -> bool:
140+
def _install_pre_commit_hook(self, hook_types: Optional[List[str]] =None) -> bool:
130141
pre_commit_config_filename = ".pre-commit-config.yaml"
131142
cz_hook_config = {
132143
"repo": "https://github.com/commitizen-tools/commitizen",
133144
"rev": f"v{__version__}",
134-
"hooks": [{"id": "commitizen"}],
145+
"hooks": [
146+
{"id": "commitizen"},
147+
{"id": "commitizen-branch", "stages": ["push"]},
148+
],
135149
}
136150

137151
config_data = {}
@@ -162,7 +176,9 @@ def _install_pre_commit_hook(self) -> bool:
162176
out.error("pre-commit is not installed in current environement.")
163177
return False
164178

165-
if not self._exec_install_pre_commit_hook():
179+
if hook_types is None:
180+
hook_types = ["commit-msg", "pre-push"]
181+
if not self._exec_install_pre_commit_hook(hook_types):
166182
return False
167183

168184
out.write("commitizen pre-commit hook is now installed in your '.git'\n")

‎tests/commands/test_init_command.py‎

Lines changed: 45 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import json
22
import os
3+
from typing import Any, Dict, List
34

45
import pytest
56
import yaml
@@ -22,7 +23,10 @@ def ask(self):
2223
cz_hook_config = {
2324
"repo": "https://github.com/commitizen-tools/commitizen",
2425
"rev": f"v{__version__}",
25-
"hooks": [{"id": "commitizen"}],
26+
"hooks": [
27+
{"id": "commitizen"},
28+
{"id": "commitizen-branch", "stages": ["push"]},
29+
],
2630
}
2731

2832
expected_config = (
@@ -51,7 +55,8 @@ def test_init_without_setup_pre_commit_hook(tmpdir, mocker: MockFixture, config)
5155
)
5256
mocker.patch("questionary.confirm", return_value=FakeQuestion(True))
5357
mocker.patch("questionary.text", return_value=FakeQuestion("$version"))
54-
mocker.patch("questionary.confirm", return_value=FakeQuestion(False))
58+
# Return None to skip hook installation
59+
mocker.patch("questionary.checkbox", return_value=FakeQuestion(None))
5560

5661
with tmpdir.as_cwd():
5762
commands.Init(config)()
@@ -118,51 +123,55 @@ def default_choice(request, mocker: MockFixture):
118123
)
119124
mocker.patch("questionary.confirm", return_value=FakeQuestion(True))
120125
mocker.patch("questionary.text", return_value=FakeQuestion("$version"))
126+
mocker.patch(
127+
"questionary.checkbox",
128+
return_value=FakeQuestion(["commit-msg", "pre-push"]),
129+
)
121130
yield request.param
122131

123132

133+
def check_cz_config(config: str):
134+
"""
135+
Cehck the content of commitizen config is as expected
136+
137+
Args:
138+
config: The config path
139+
"""
140+
with open(config, "r") as file:
141+
if "json" in config:
142+
assert json.load(file) == EXPECTED_DICT_CONFIG
143+
elif "yaml" in config:
144+
assert yaml.load(file, Loader=yaml.FullLoader) == EXPECTED_DICT_CONFIG
145+
else:
146+
config_data = file.read()
147+
assert config_data == expected_config
148+
149+
150+
def check_pre_commit_config(expected: List[Dict[str, Any]]):
151+
"""
152+
Check the content of pre-commit config is as expected
153+
"""
154+
with open(pre_commit_config_filename, "r") as pre_commit_file:
155+
pre_commit_config_data = yaml.safe_load(pre_commit_file.read())
156+
assert pre_commit_config_data == {"repos": expected}
157+
158+
124159
@pytest.mark.usefixtures("pre_commit_installed")
125160
class TestPreCommitCases:
126161
def test_no_existing_pre_commit_conifg(_, default_choice, tmpdir, config):
127162
with tmpdir.as_cwd():
128163
commands.Init(config)()
129-
130-
with open(default_choice, "r") as file:
131-
if "json" in default_choice:
132-
assert json.load(file) == EXPECTED_DICT_CONFIG
133-
elif "yaml" in default_choice:
134-
assert (
135-
yaml.load(file, Loader=yaml.FullLoader) == EXPECTED_DICT_CONFIG
136-
)
137-
else:
138-
config_data = file.read()
139-
assert config_data == expected_config
140-
141-
with open(pre_commit_config_filename, "r") as pre_commit_file:
142-
pre_commit_config_data = yaml.safe_load(pre_commit_file.read())
143-
assert pre_commit_config_data == {"repos": [cz_hook_config]}
164+
check_cz_config(default_choice)
165+
check_pre_commit_config([cz_hook_config])
144166

145167
def test_empty_pre_commit_config(_, default_choice, tmpdir, config):
146168
with tmpdir.as_cwd():
147169
p = tmpdir.join(pre_commit_config_filename)
148170
p.write("")
149171

150172
commands.Init(config)()
151-
152-
with open(default_choice, "r") as file:
153-
if "json" in default_choice:
154-
assert json.load(file) == EXPECTED_DICT_CONFIG
155-
elif "yaml" in default_choice:
156-
assert (
157-
yaml.load(file, Loader=yaml.FullLoader) == EXPECTED_DICT_CONFIG
158-
)
159-
else:
160-
config_data = file.read()
161-
assert config_data == expected_config
162-
163-
with open(pre_commit_config_filename, "r") as pre_commit_file:
164-
pre_commit_config_data = yaml.safe_load(pre_commit_file.read())
165-
assert pre_commit_config_data == {"repos": [cz_hook_config]}
173+
check_cz_config(default_choice)
174+
check_pre_commit_config([cz_hook_config])
166175

167176
def test_pre_commit_config_without_cz_hook(_, default_choice, tmpdir, config):
168177
existing_hook_config = {
@@ -176,47 +185,18 @@ def test_pre_commit_config_without_cz_hook(_, default_choice, tmpdir, config):
176185
p.write(yaml.safe_dump({"repos": [existing_hook_config]}))
177186

178187
commands.Init(config)()
179-
180-
with open(default_choice, "r") as file:
181-
if "json" in default_choice:
182-
assert json.load(file) == EXPECTED_DICT_CONFIG
183-
elif "yaml" in default_choice:
184-
assert (
185-
yaml.load(file, Loader=yaml.FullLoader) == EXPECTED_DICT_CONFIG
186-
)
187-
else:
188-
config_data = file.read()
189-
assert config_data == expected_config
190-
191-
with open(pre_commit_config_filename, "r") as pre_commit_file:
192-
pre_commit_config_data = yaml.safe_load(pre_commit_file.read())
193-
assert pre_commit_config_data == {
194-
"repos": [existing_hook_config, cz_hook_config]
195-
}
188+
check_cz_config(default_choice)
189+
check_pre_commit_config([existing_hook_config, cz_hook_config])
196190

197191
def test_cz_hook_exists_in_pre_commit_config(_, default_choice, tmpdir, config):
198192
with tmpdir.as_cwd():
199193
p = tmpdir.join(pre_commit_config_filename)
200194
p.write(yaml.safe_dump({"repos": [cz_hook_config]}))
201195

202196
commands.Init(config)()
203-
204-
with open(default_choice, "r") as file:
205-
if "json" in default_choice:
206-
assert json.load(file) == EXPECTED_DICT_CONFIG
207-
elif "yaml" in default_choice:
208-
assert (
209-
yaml.load(file, Loader=yaml.FullLoader) == EXPECTED_DICT_CONFIG
210-
)
211-
else:
212-
config_data = file.read()
213-
assert config_data == expected_config
214-
215-
with open(pre_commit_config_filename, "r") as pre_commit_file:
216-
pre_commit_config_data = yaml.safe_load(pre_commit_file.read())
217-
197+
check_cz_config(default_choice)
218198
# check that config is not duplicated
219-
assertpre_commit_config_data== {"repos": [cz_hook_config]}
199+
check_pre_commit_config([cz_hook_config])
220200

221201

222202
class TestNoPreCommitInstalled:

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /