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 968a900

Browse files
committed
feat(commit): implement questions 'filter' support with handlers
Supported APIs: - multiple_line_breaker - required_validator - required_validator_scope - required_validator_subject_strip - required_validator_title_strip Example YAML configurations: --- commitizen: name: cz_customize customize: questions: - ... - type: input name: scope message: 'Scope of the change :' filter: 'required_validator_scope' default: '' - type: input name: subject message: 'Title of the commit (starting in lower case and without period) :' filter: 'required_validator_subject_strip' default: '' - type: input name: body message: 'Additional contextual message (Empty to skip) :' default: 'Issue: #...' filter: 'multiple_line_breaker' --- Signed-off-by: Adrian DC <radian.dc@gmail.com>
1 parent 5e08775 commit 968a900

File tree

4 files changed

+113
-5
lines changed

4 files changed

+113
-5
lines changed

‎commitizen/commands/commit.py‎

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,14 @@
88
from commitizen import factory, git, out
99
from commitizen.config import BaseConfig
1010
from commitizen.cz.exceptions import CzException
11-
from commitizen.cz.utils import get_backup_file_path
11+
from commitizen.cz.utils import (
12+
get_backup_file_path,
13+
multiple_line_breaker,
14+
required_validator,
15+
required_validator_scope,
16+
required_validator_subject_strip,
17+
required_validator_title_strip,
18+
)
1219
from commitizen.exceptions import (
1320
CommitError,
1421
CommitMessageLengthExceededError,
@@ -52,6 +59,23 @@ def prompt_commit_questions(self) -> str:
5259

5360
for question in filter(lambda q: q["type"] == "list", questions):
5461
question["use_shortcuts"] = self.config.settings["use_shortcuts"]
62+
63+
for question in filter(
64+
lambda q: isinstance(q.get("filter", None), str), questions
65+
):
66+
if question["filter"] == "multiple_line_breaker":
67+
question["filter"] = multiple_line_breaker
68+
elif question["filter"] == "required_validator":
69+
question["filter"] = required_validator
70+
elif question["filter"] == "required_validator_scope":
71+
question["filter"] = required_validator_scope
72+
elif question["filter"] == "required_validator_subject_strip":
73+
question["filter"] = required_validator_subject_strip
74+
elif question["filter"] == "required_validator_title_strip":
75+
question["filter"] = required_validator_title_strip
76+
else:
77+
raise NotAllowed(f"Unknown value filter: {question['filter']}")
78+
5579
try:
5680
answers = questionary.prompt(questions, style=cz.style)
5781
except ValueError as err:

‎commitizen/cz/utils.py‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@ def required_validator(answer, msg=None):
1212
return answer
1313

1414

15+
def required_validator_scope(answer, msg="! Error: Scope is required"):
16+
return required_validator(answer, msg)
17+
18+
19+
def required_validator_subject_strip(answer, msg="! Error: Subject is required"):
20+
return required_validator(answer.strip(".").strip(), msg)
21+
22+
23+
def required_validator_title_strip(answer, msg="! Error: Title is required"):
24+
return required_validator(answer.strip(".").strip(), msg)
25+
26+
1527
def multiple_line_breaker(answer, sep="|"):
1628
return "\n".join(line.strip() for line in answer.split(sep) if line)
1729

‎docs/customization.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ commitizen:
175175
| `message` | `str` | `None` | Detail description for the question. |
176176
| `choices` | `list` | `None` | (OPTIONAL) The choices when `type = list`. Either use a list of values or a list of dictionaries with `name` and `value` keys. Keyboard shortcuts can be defined via `key`. See examples above. |
177177
| `default` | `Any` | `None` | (OPTIONAL) The default value for this question. |
178-
| `filter` | `str` | `None` | (Optional) Validator for user's answer. **(Work in Progress)** |
178+
| `filter` | `str` | `None` | (OPTIONAL) Validator for user's answer. The string is the name of a `commitizen.cz.utils.NAME(answer...)` function like `multiple_line_breaker` |
179179
[different-question-types]: https://github.com/tmbo/questionary#different-question-types
180180

181181
#### Shortcut keys

‎tests/test_cz_customize.py‎

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import pytest
2+
from pytest_mock import MockFixture
23

4+
from commitizen import cmd, commands
35
from commitizen.config import BaseConfig, JsonConfig, TomlConfig, YAMLConfig
46
from commitizen.cz.customize import CustomizeCommitsCz
7+
from commitizen.cz.utils import multiple_line_breaker, required_validator_subject_strip
58
from commitizen.exceptions import MissingCzCustomizeConfigError
69

710
TOML_STR = r"""
@@ -36,10 +39,17 @@
3639
]
3740
message = "Select the type of change you are committing"
3841
42+
[[tool.commitizen.customize.questions]]
43+
type = "input"
44+
name = "subject"
45+
message = "Subject."
46+
filter = "required_validator_subject_strip"
47+
3948
[[tool.commitizen.customize.questions]]
4049
type = "input"
4150
name = "message"
4251
message = "Body."
52+
filter = "multiple_line_breaker"
4353
4454
[[tool.commitizen.customize.questions]]
4555
type = "confirm"
@@ -89,10 +99,17 @@
8999
],
90100
"message": "Select the type of change you are committing"
91101
},
102+
{
103+
"type": "input",
104+
"name": "subject",
105+
"message": "Subject.",
106+
"filter": "required_validator_subject_strip"
107+
},
92108
{
93109
"type": "input",
94110
"name": "message",
95-
"message": "Body."
111+
"message": "Body.",
112+
"filter": "multiple_line_breaker"
96113
},
97114
{
98115
"type": "confirm",
@@ -139,9 +156,14 @@
139156
- value: bug fix
140157
name: 'bug fix: A bug fix.'
141158
message: Select the type of change you are committing
159+
- type: input
160+
name: subject
161+
message: Subject.
162+
filter: required_validator_subject_strip
142163
- type: input
143164
name: message
144165
message: Body.
166+
filter: multiple_line_breaker
145167
- type: confirm
146168
name: show_message
147169
message: Do you want to add body message in commit?
@@ -330,6 +352,13 @@
330352
"""
331353

332354

355+
@pytest.fixture
356+
def staging_is_clean(mocker: MockFixture, tmp_git_project):
357+
is_staging_clean_mock = mocker.patch("commitizen.git.is_staging_clean")
358+
is_staging_clean_mock.return_value = False
359+
return tmp_git_project
360+
361+
333362
@pytest.fixture(
334363
params=[
335364
TomlConfig(data=TOML_STR, path="not_exist.toml"),
@@ -437,7 +466,7 @@ def test_change_type_order_unicode(config_with_unicode):
437466
]
438467

439468

440-
def test_questions(config):
469+
def test_questions_default(config):
441470
cz = CustomizeCommitsCz(config)
442471
questions = cz.questions()
443472
expected_questions = [
@@ -450,7 +479,18 @@ def test_questions(config):
450479
],
451480
"message": "Select the type of change you are committing",
452481
},
453-
{"type": "input", "name": "message", "message": "Body."},
482+
{
483+
"type": "input",
484+
"name": "subject",
485+
"message": "Subject.",
486+
"filter": "required_validator_subject_strip",
487+
},
488+
{
489+
"type": "input",
490+
"name": "message",
491+
"message": "Body.",
492+
"filter": "multiple_line_breaker",
493+
},
454494
{
455495
"type": "confirm",
456496
"name": "show_message",
@@ -460,6 +500,38 @@ def test_questions(config):
460500
assert list(questions) == expected_questions
461501

462502

503+
@pytest.mark.usefixtures("staging_is_clean")
504+
def test_questions_filter(config, mocker: MockFixture):
505+
is_staging_clean_mock = mocker.patch("commitizen.git.is_staging_clean")
506+
is_staging_clean_mock.return_value = False
507+
508+
prompt_mock = mocker.patch("questionary.prompt")
509+
prompt_mock.return_value = {
510+
"change_type": "feature",
511+
"subject": "user created",
512+
"message": "body of the commit",
513+
"show_message": True,
514+
}
515+
516+
commit_mock = mocker.patch("commitizen.git.commit")
517+
commit_mock.return_value = cmd.Command("success", "", b"", b"", 0)
518+
519+
commands.Commit(config, {})()
520+
521+
prompts_questions = prompt_mock.call_args[0][0]
522+
assert prompts_questions[0]["type"] == "list"
523+
assert prompts_questions[0]["name"] == "change_type"
524+
assert prompts_questions[0]["use_shortcuts"] is False
525+
assert prompts_questions[1]["type"] == "input"
526+
assert prompts_questions[1]["name"] == "subject"
527+
assert prompts_questions[1]["filter"] == required_validator_subject_strip
528+
assert prompts_questions[2]["type"] == "input"
529+
assert prompts_questions[2]["name"] == "message"
530+
assert prompts_questions[2]["filter"] == multiple_line_breaker
531+
assert prompts_questions[3]["type"] == "confirm"
532+
assert prompts_questions[3]["name"] == "show_message"
533+
534+
463535
def test_questions_unicode(config_with_unicode):
464536
cz = CustomizeCommitsCz(config_with_unicode)
465537
questions = cz.questions()

0 commit comments

Comments
(0)

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