From efaaea0bf2f5821a67322d1b16fe44aabe5eb567 Mon Sep 17 00:00:00 2001 From: Zev Isert Date: Fri, 16 Jul 2021 19:09:45 -0700 Subject: [PATCH 1/6] feat(prompt): add keyboard shortcuts with config option --- .../conventional_commits.py | 17 +++++++++++++++-- commitizen/defaults.py | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index 6ac62d5ec1..d51e8bdf20 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -45,16 +45,23 @@ def questions(self) -> List[Dict[str, Any]]: "type": "list", "name": "prefix", "message": "Select the type of change you are committing", + "use_shortcuts": self.config.settings['use_shortcuts'], "choices": [ { "value": "fix", "name": "fix: A bug fix. Correlates with PATCH in SemVer", + "key": "x", }, { "value": "feat", "name": "feat: A new feature. Correlates with MINOR in SemVer", + "key": "f", + }, + { + "value": "docs", + "name": "docs: Documentation only changes", + "key": "d", }, - {"value": "docs", "name": "docs: Documentation only changes"}, { "value": "style", "name": ( @@ -62,6 +69,7 @@ def questions(self) -> List[Dict[str, Any]]: "meaning of the code (white-space, formatting," " missing semi-colons, etc)" ), + "key": "s", }, { "value": "refactor", @@ -69,16 +77,19 @@ def questions(self) -> List[Dict[str, Any]]: "refactor: A code change that neither fixes " "a bug nor adds a feature" ), + "key": "r", }, { "value": "perf", "name": "perf: A code change that improves performance", + "key": "p", }, { "value": "test", "name": ( "test: Adding missing or correcting " "existing tests" ), + "key": "t", }, { "value": "build", @@ -86,6 +97,7 @@ def questions(self) -> List[Dict[str, Any]]: "build: Changes that affect the build system or " "external dependencies (example scopes: pip, docker, npm)" ), + "key": "b", }, { "value": "ci", @@ -93,7 +105,8 @@ def questions(self) -> List[Dict[str, Any]]: "ci: Changes to our CI configuration files and " "scripts (example scopes: GitLabCI)" ), - }, + "key": "c", + } ], }, { diff --git a/commitizen/defaults.py b/commitizen/defaults.py index 83f2ca4636..5d21f67a98 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -21,6 +21,7 @@ "changelog_incremental": False, "changelog_start_rev": None, "update_changelog_on_bump": False, + "use_shortcuts": False, } MAJOR = "MAJOR" From 769540d4741a219a0d153682fe77fdf4e3a96cb8 Mon Sep 17 00:00:00 2001 From: Zev Isert Date: Fri, 6 Aug 2021 11:39:15 -0700 Subject: [PATCH 2/6] test: update tests for keyboard shortcuts Only testing that cz_conventional_commits has keyboard shortcuts configured, and that the use_shortcuts config option is known. Actually mocking and asserting against what's written to stdout is a footgun #406, #380 --- tests/test_conf.py | 2 ++ tests/test_cz_conventional_commits.py | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/tests/test_conf.py b/tests/test_conf.py index f05603cfe4..786af25756 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -46,6 +46,7 @@ "changelog_incremental": False, "changelog_start_rev": None, "update_changelog_on_bump": False, + "use_shortcuts": False, } _new_settings = { @@ -59,6 +60,7 @@ "changelog_incremental": False, "changelog_start_rev": None, "update_changelog_on_bump": False, + "use_shortcuts": False, } _read_settings = { diff --git a/tests/test_cz_conventional_commits.py b/tests/test_cz_conventional_commits.py index e43284a121..6a3b538ed3 100644 --- a/tests/test_cz_conventional_commits.py +++ b/tests/test_cz_conventional_commits.py @@ -62,6 +62,15 @@ def test_questions(config): assert isinstance(questions[0], dict) +def test_choices_all_have_keyboard_shortcuts(config): + conventional_commits = ConventionalCommitsCz(config) + questions = conventional_commits.questions() + + list_questions = (q for q in questions if q['type'] == "list") + for select in list_questions: + assert all('key' in choice for choice in select['choices']) + + def test_small_answer(config): conventional_commits = ConventionalCommitsCz(config) answers = { From 433383c0081504d6fddfc29446b076cd123c44fa Mon Sep 17 00:00:00 2001 From: Zev Isert Date: Mon, 9 Aug 2021 09:42:35 -0700 Subject: [PATCH 3/6] style: formatting --- commitizen/cz/conventional_commits/conventional_commits.py | 4 ++-- commitizen/defaults.py | 2 +- tests/test_cz_conventional_commits.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index d51e8bdf20..fea3d61848 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -45,7 +45,7 @@ def questions(self) -> List[Dict[str, Any]]: "type": "list", "name": "prefix", "message": "Select the type of change you are committing", - "use_shortcuts": self.config.settings['use_shortcuts'], + "use_shortcuts": self.config.settings["use_shortcuts"], "choices": [ { "value": "fix", @@ -106,7 +106,7 @@ def questions(self) -> List[Dict[str, Any]]: "scripts (example scopes: GitLabCI)" ), "key": "c", - } + }, ], }, { diff --git a/commitizen/defaults.py b/commitizen/defaults.py index 5d21f67a98..e460bbd6f7 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -21,7 +21,7 @@ "changelog_incremental": False, "changelog_start_rev": None, "update_changelog_on_bump": False, - "use_shortcuts": False, + "use_shortcuts": False, } MAJOR = "MAJOR" diff --git a/tests/test_cz_conventional_commits.py b/tests/test_cz_conventional_commits.py index 6a3b538ed3..b84144e94c 100644 --- a/tests/test_cz_conventional_commits.py +++ b/tests/test_cz_conventional_commits.py @@ -66,9 +66,9 @@ def test_choices_all_have_keyboard_shortcuts(config): conventional_commits = ConventionalCommitsCz(config) questions = conventional_commits.questions() - list_questions = (q for q in questions if q['type'] == "list") + list_questions = (q for q in questions if q["type"] == "list") for select in list_questions: - assert all('key' in choice for choice in select['choices']) + assert all("key" in choice for choice in select["choices"]) def test_small_answer(config): From f32e7b85a2ab7a11b0b8afa5e3b0dbac13cafbd5 Mon Sep 17 00:00:00 2001 From: Zev Isert Date: Wed, 11 Aug 2021 18:40:41 -0700 Subject: [PATCH 4/6] refactor(shortcuts): move check for shortcut config setting to apply to any list select --- commitizen/commands/commit.py | 2 ++ commitizen/cz/conventional_commits/conventional_commits.py | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index 4c6f7aa03c..ac646a0220 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -46,6 +46,8 @@ def prompt_commit_questions(self) -> str: # Prompt user for the commit message cz = self.cz questions = cz.questions() + for question in filter(lambda q: q['type'] == 'list', questions): + question["use_shortcuts"] = self.config.settings["use_shortcuts"] try: answers = questionary.prompt(questions, style=cz.style) except ValueError as err: diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index fea3d61848..61f7b7f94b 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -45,7 +45,6 @@ def questions(self) -> List[Dict[str, Any]]: "type": "list", "name": "prefix", "message": "Select the type of change you are committing", - "use_shortcuts": self.config.settings["use_shortcuts"], "choices": [ { "value": "fix", From 428b30d9e83efd03749afcc877a46702ccf01813 Mon Sep 17 00:00:00 2001 From: Zev Isert Date: Wed, 11 Aug 2021 18:43:13 -0700 Subject: [PATCH 5/6] docs(shortcuts): update to include info about keyboard shortcut options --- docs/config.md | 28 +++++++++++++++--------- docs/customization.md | 51 +++++++++++++++++++++++++------------------ 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/docs/config.md b/docs/config.md index 204edcf887..eee90e1dcc 100644 --- a/docs/config.md +++ b/docs/config.md @@ -122,13 +122,21 @@ commitizen: ## Settings -| Variable | Type | Default | Description | -| -------- | ---- | ------- | ----------- | -| `name` | `str` | `"cz_conventional_commits"` | Name of the committing rules to use | -| `version` | `str` | `None` | Current version. Example: "0.1.2" | -| `version_files` | `list` | `[ ]` | Files were the version will be updated. A pattern to match a line, can also be specified, separated by `:` [See more](https://commitizen-tools.github.io/commitizen/bump/#version_files) | -| `tag_format` | `str` | `None` | Format for the git tag, useful for old projects, that use a convention like `"v1.2.1"`. [See more](https://commitizen-tools.github.io/commitizen/bump/#tag_format) | -| `bump_message` | `str` | `None` | Create custom commit message, useful to skip ci. [See more](https://commitizen-tools.github.io/commitizen/bump/#bump_message) | -| `changelog_file` | `str` | `CHANGELOG.md` | filename of exported changelog | -| `style` | `list` | see above | Style for the prompts (It will merge this value with default style.) [See More (Styling your prompts with your favorite colors)](https://github.com/tmbo/questionary#additional-features) | -| `customize` | `dict` | `None` | **This is only supported when config through `toml`.** Custom rules for committing and bumping. [See more](https://commitizen-tools.github.io/commitizen/customization/) | +| Variable | Type | Default | Description | +| ---------------- | ------ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `name` | `str` | `"cz_conventional_commits"` | Name of the committing rules to use | +| `version` | `str` | `None` | Current version. Example: "0.1.2" | +| `version_files` | `list` | `[ ]` | Files were the version will be updated. A pattern to match a line, can also be specified, separated by `:` [See more](version_files) | +| `tag_format` | `str` | `None` | Format for the git tag, useful for old projects, that use a convention like `"v1.2.1"`. [See more](tag_format) | +| `bump_message` | `str` | `None` | Create custom commit message, useful to skip ci. [See more](bump_message) | +| `changelog_file` | `str` | `CHANGELOG.md` | filename of exported changelog | +| `style` | `list` | see above | Style for the prompts (It will merge this value with default style.) [See More (Styling your prompts with your favorite colors)](additional-features) | +| `customize` | `dict` | `None` | **This is only supported when config through `toml`.** Custom rules for committing and bumping. [See more](customization) | +| `use_shortcuts` | `bool` | `false` | If enabled, commitizen will show keyboard shortcuts when selecting from a list. Define a `key` for each of your choices to set the key. [See more](shortcuts) | + +[version_files]: https://commitizen-tools.github.io/commitizen/bump/#version_files +[tag_format]: https://commitizen-tools.github.io/commitizen/bump/#tag_format +[bump_message]: https://commitizen-tools.github.io/commitizen/bump/#bump_message +[additional-features]: https://github.com/tmbo/questionary#additional-features +[customization]: https://commitizen-tools.github.io/commitizen/customization/ +[shortcuts]: https://commitizen-tools.github.io/commitizen/customization/#shortcut-keys diff --git a/docs/customization.md b/docs/customization.md index 3492d8288c..b96c459e41 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -138,30 +138,39 @@ commitizen: ### Customize configuration -| Parameter | Type | Default | Description | -| ------------------ | ------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `questions` | `dict` | `None` | Questions regarding the commit message. Detailed below. | -| `message_template` | `str` | `None` | The template for generating message from the given answers. `message_template` should either follow [Jinja2](https://jinja.palletsprojects.com/en/2.10.x/) formatting specification, and all the variables in this template should be defined in `name` in `questions` | -| `example` | `str` | `None` | (OPTIONAL) Provide an example to help understand the style. Used by `cz example`. | -| `schema` | `str` | `None` | (OPTIONAL) Show the schema used. Used by `cz schema`. | -| `schema_pattern` | `str` | `None` | (OPTIONAL) The regular expression used to do commit message validation. Used by `cz check`. | -| `info_path` | `str` | `None` | (OPTIONAL) The path to the file that contains explanation of the commit rules. Used by `cz info`. If not provided `cz info`, will load `info` instead. | -| `info` | `str` | `None` | (OPTIONAL) Explanation of the commit rules. Used by `cz info`. | -| `bump_map` | `dict` | `None` | (OPTIONAL) Dictionary mapping the extracted information to a `SemVer` increment type (`MAJOR`, `MINOR`, `PATCH`) | -| `bump_pattern` | `str` | `None` | (OPTIONAL) Regex to extract information from commit (subject and body) | -| `change_type_order`| `str` | `None` | (OPTIONAL) List of strings used to order the Changelog. All other types will be sorted alphabetically. Default is `["BREAKING CHANGE", "feat", "fix", "refactor", "perf"]` | - +| Parameter | Type | Default | Description | +| ------------------- | ------ | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `questions` | `dict` | `None` | Questions regarding the commit message. Detailed below. | +| `message_template` | `str` | `None` | The template for generating message from the given answers. `message_template` should either follow [Jinja2][jinja2] formatting specification, and all the variables in this template should be defined in `name` in `questions` | +| `example` | `str` | `None` | (OPTIONAL) Provide an example to help understand the style. Used by `cz example`. | +| `schema` | `str` | `None` | (OPTIONAL) Show the schema used. Used by `cz schema`. | +| `schema_pattern` | `str` | `None` | (OPTIONAL) The regular expression used to do commit message validation. Used by `cz check`. | +| `info_path` | `str` | `None` | (OPTIONAL) The path to the file that contains explanation of the commit rules. Used by `cz info`. If not provided `cz info`, will load `info` instead. | +| `info` | `str` | `None` | (OPTIONAL) Explanation of the commit rules. Used by `cz info`. | +| `bump_map` | `dict` | `None` | (OPTIONAL) Dictionary mapping the extracted information to a `SemVer` increment type (`MAJOR`, `MINOR`, `PATCH`) | +| `bump_pattern` | `str` | `None` | (OPTIONAL) Regex to extract information from commit (subject and body) | +| `change_type_order` | `str` | `None` | (OPTIONAL) List of strings used to order the Changelog. All other types will be sorted alphabetically. Default is `["BREAKING CHANGE", "feat", "fix", "refactor", "perf"]` | + +[jinja2]: https://jinja.palletsprojects.com/en/2.10.x/ #### Detailed `questions` content -| Parameter | Type | Default | Description | -| --------- | ------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| `type` | `str` | `None` | The type of questions. Valid type: `list`, `input` and etc. [See More](https://github.com/tmbo/questionary#different-question-types) | -| `name` | `str` | `None` | The key for the value answered by user. It's used in `message_template` | -| `message` | `str` | `None` | Detail description for the question. | -| `choices` | `list` | `None` | (OPTIONAL) The choices when `type = list`. Either use a list of values or a list of dicitionaries with `name` and `value` keys. See examples above. | -| `default` | `Any` | `None` | (OPTIONAL) The default value for this question. | -| `filter` | `str` | `None` | (Optional) Validator for user's answer. **(Work in Progress)** | +| Parameter | Type | Default | Description | +| --------- | ------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `type` | `str` | `None` | The type of questions. Valid type: `list`, `input` and etc. [See More][different-question-types] | +| `name` | `str` | `None` | The key for the value answered by user. It's used in `message_template` | +| `message` | `str` | `None` | Detail description for the question. | +| `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. | +| `default` | `Any` | `None` | (OPTIONAL) The default value for this question. | +| `filter` | `str` | `None` | (Optional) Validator for user's answer. **(Work in Progress)** | + +[different-question-types]: https://github.com/tmbo/questionary#different-question-types + +#### Shortcut keys +When the [`use_shortcuts`](https://commitizen-tools.github.io/commitizen/config/#settings) config option is enabled, commitizen can show and use keyboard shortcuts to select items from lists directly. +For example, when using the `cz_conventional_commits` commitizen template, shortcut keys are shown when selecting the commit type. Unless otherwise defined, keyboard shortcuts will be numbered automatically. +To specify keyboard shortcuts for your custom choices, provide the shortcut using the `key` parameter in dictionary form for each choice you would like to customize. + ## 2. Customize through customizing a class The basic steps are: From 50ddc72d9b802f3373ee17cbd320df4e92e55b45 Mon Sep 17 00:00:00 2001 From: Zev Isert Date: Wed, 11 Aug 2021 18:45:20 -0700 Subject: [PATCH 6/6] style: forgot to run black --- commitizen/commands/commit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index ac646a0220..bad47dd572 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -46,7 +46,7 @@ def prompt_commit_questions(self) -> str: # Prompt user for the commit message cz = self.cz questions = cz.questions() - for question in filter(lambda q: q['type'] == 'list', questions): + for question in filter(lambda q: q["type"] == "list", questions): question["use_shortcuts"] = self.config.settings["use_shortcuts"] try: answers = questionary.prompt(questions, style=cz.style)