Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@

from commitizen import defaults
from commitizen.cz.base import BaseCommitizen
from commitizen.cz.utils import multiple_line_breaker, required_validator
from commitizen.cz.utils import (
get_multiline_key_bindings,
multiple_line_breaker,
required_validator,
)

if TYPE_CHECKING:
from commitizen.question import CzQuestion
Expand Down Expand Up @@ -133,6 +137,8 @@ def questions(self) -> list[CzQuestion]:
"Provide additional contextual information about the code changes: (press [enter] to skip)\n"
),
"filter": multiple_line_breaker,
"multiline": True,
"key_bindings": get_multiline_key_bindings(),
},
{
"type": "confirm",
Expand Down
19 changes: 19 additions & 0 deletions commitizen/cz/utils.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
import os
import re
import tempfile
from functools import lru_cache
from pathlib import Path

from prompt_toolkit.key_binding import KeyBindings, KeyPressEvent
from prompt_toolkit.keys import Keys

from commitizen import git
from commitizen.cz import exceptions

_RE_LOCAL_VERSION = re.compile(r"\+.+")


@lru_cache(maxsize=1)
def get_multiline_key_bindings() -> KeyBindings:
kb = KeyBindings()

@kb.add(Keys.Enter)
def handle_enter(event: KeyPressEvent) -> None:
buff = event.app.current_buffer
if buff.text == "":
buff.validate_and_handle()
else:
buff.insert_text("\n")

return kb


def required_validator(answer: str, msg: object = None) -> str:
if not answer:
raise exceptions.AnswerRequiredError(msg)
Expand Down
4 changes: 4 additions & 0 deletions commitizen/question.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from collections.abc import Callable
from typing import Literal, TypedDict

from prompt_toolkit.key_binding import KeyBindings


class Choice(TypedDict, total=False):
value: str
Expand All @@ -21,6 +23,8 @@ class InputQuestion(TypedDict, total=False):
name: str
message: str
filter: Callable[[str], str]
multiline: bool
key_bindings: KeyBindings


class ConfirmQuestion(TypedDict):
Expand Down
Binary file modified docs/images/cli_interactive/bump.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/cli_interactive/commit.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/cli_interactive/init.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/cli_interactive/shortcut_custom.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/cli_interactive/shortcut_default.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions tests/test_cz_conventional_commits.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pytest
from prompt_toolkit.key_binding import KeyBindings

from commitizen.cz.conventional_commits.conventional_commits import (
ConventionalCommitsCz,
Expand Down Expand Up @@ -173,3 +174,10 @@ def test_info(config):
conventional_commits = ConventionalCommitsCz(config)
info = conventional_commits.info()
assert isinstance(info, str)


def test_body_question_is_multiline(config):
cz = ConventionalCommitsCz(config)
body_question = next(q for q in cz.questions() if q["name"] == "body")
assert body_question["multiline"] is True
assert isinstance(body_question["key_bindings"], KeyBindings)
29 changes: 29 additions & 0 deletions tests/test_cz_utils.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,38 @@
import pytest
from prompt_toolkit.keys import Keys
from pytest_mock import MockFixture

from commitizen.cz import exceptions, utils


def test_multiline_key_bindings_enter_submits_on_empty(mocker: MockFixture):
kb = utils.get_multiline_key_bindings()
handler = next(b.handler for b in kb.bindings if Keys.Enter in b.keys)

buff = mocker.MagicMock()
buff.text = ""
event = mocker.MagicMock()
event.app.current_buffer = buff

handler(event)
buff.validate_and_handle.assert_called_once()
buff.insert_text.assert_not_called()


def test_multiline_key_bindings_enter_inserts_newline(mocker: MockFixture):
kb = utils.get_multiline_key_bindings()
handler = next(b.handler for b in kb.bindings if Keys.Enter in b.keys)

buff = mocker.MagicMock()
buff.text = "some content"
event = mocker.MagicMock()
event.app.current_buffer = buff

handler(event)
buff.insert_text.assert_called_once_with("\n")
buff.validate_and_handle.assert_not_called()


def test_required_validator():
assert utils.required_validator("test") == "test"

Expand Down
Loading