From d968daf1271e3cb1126be1eb62939a2b41badbf0 Mon Sep 17 00:00:00 2001 From: LeeW Date: Tue, 19 Nov 2019 10:50:33 -0500 Subject: [PATCH 1/7] feat(cz/filters): add required_validator and multiple_line_breaker --- commitizen/commands/bump.py | 2 +- .../cz/conventional_commits/conventional_commits.py | 12 +++--------- commitizen/cz/exceptions.py | 4 ++++ commitizen/cz/filters.py | 11 +++++++++++ tests/test_cz_conventional_commits.py | 4 ++-- 5 files changed, 21 insertions(+), 12 deletions(-) create mode 100644 commitizen/cz/filters.py diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 89cec1153a..d017f8a7a6 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -122,7 +122,7 @@ def __call__(self): bump.update_version_in_files(current_version, new_version.public, files) c = git.commit(message, args="-a") if c.err: - out.error("git.commit errror: \"{}\"".format(c.err.strip())) + out.error('git.commit errror: "{}"'.format(c.err.strip())) raise SystemExit(COMMIT_FAILED) c = git.tag(new_tag_version) if c.err: diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index 401e8cdf91..0d6d274ba1 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -2,15 +2,11 @@ from commitizen import defaults from commitizen.cz.base import BaseCommitizen -from commitizen.cz.exceptions import CzException +from commitizen.cz.filters import multiple_line_breaker, required_validator __all__ = ["ConventionalCommitsCz"] -class NoSubjectException(CzException): - ... - - def parse_scope(text): if not text: return "" @@ -26,10 +22,7 @@ def parse_subject(text): if isinstance(text, str): text = text.strip(".").strip() - if not text: - raise NoSubjectException("Subject is required.") - - return text + return required_validator(text, msg="Subject is required.") class ConventionalCommitsCz(BaseCommitizen): @@ -124,6 +117,7 @@ def questions(self) -> list: "Body. Motivation for the change and contrast this " "with previous behavior:\n" ), + "filter": multiple_line_breaker, }, { "type": "input", diff --git a/commitizen/cz/exceptions.py b/commitizen/cz/exceptions.py index 2b070ff57d..89b19788b7 100644 --- a/commitizen/cz/exceptions.py +++ b/commitizen/cz/exceptions.py @@ -1,2 +1,6 @@ class CzException(Exception): ... + + +class AnswerRequiredError(Exception): + ... diff --git a/commitizen/cz/filters.py b/commitizen/cz/filters.py new file mode 100644 index 0000000000..0c5aedadaa --- /dev/null +++ b/commitizen/cz/filters.py @@ -0,0 +1,11 @@ +from commitizen.cz import exceptions + + +def required_validator(ans, msg=None): + if not ans: + raise exceptions.AnswerRequiredError(msg) + return ans + + +def multiple_line_breaker(ans, sep="|"): + return "\n".join(line.strip() for line in ans.split(sep) if line) diff --git a/tests/test_cz_conventional_commits.py b/tests/test_cz_conventional_commits.py index 0f6be2d624..f464ba4ae6 100644 --- a/tests/test_cz_conventional_commits.py +++ b/tests/test_cz_conventional_commits.py @@ -3,10 +3,10 @@ from commitizen import defaults from commitizen.cz.conventional_commits.conventional_commits import ( ConventionalCommitsCz, - NoSubjectException, parse_scope, parse_subject, ) +from commitizen.cz.exceptions import AnswerRequiredError config = {"name": defaults.name} @@ -39,7 +39,7 @@ def test_parse_subject_valid_values(): def test_parse_subject_invalid_values(): for valid_subject in invalid_subjects: - with pytest.raises(NoSubjectException): + with pytest.raises(AnswerRequiredError): parse_subject(valid_subject) From 4aeb28cba7d1390ae0c6b6219b1de12441fcdbea Mon Sep 17 00:00:00 2001 From: LeeW Date: Tue, 19 Nov 2019 10:51:57 -0500 Subject: [PATCH 2/7] refactor(cz/utils): rename filters as utils --- commitizen/cz/conventional_commits/conventional_commits.py | 2 +- commitizen/cz/{filters.py => utils.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename commitizen/cz/{filters.py => utils.py} (100%) diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index 0d6d274ba1..bd0ab35885 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -2,7 +2,7 @@ from commitizen import defaults from commitizen.cz.base import BaseCommitizen -from commitizen.cz.filters import multiple_line_breaker, required_validator +from commitizen.cz.utils import multiple_line_breaker, required_validator __all__ = ["ConventionalCommitsCz"] diff --git a/commitizen/cz/filters.py b/commitizen/cz/utils.py similarity index 100% rename from commitizen/cz/filters.py rename to commitizen/cz/utils.py From 948150d1222c969201a8e663393f1ae7b58c6c05 Mon Sep 17 00:00:00 2001 From: LeeW Date: Tue, 19 Nov 2019 10:56:45 -0500 Subject: [PATCH 3/7] feat(cz/customize): add jinja support to enhance template flexibility #54 --- commitizen/cz/customize/customize.py | 6 ++++-- pyproject.toml | 1 + tests/test_cz_customize.py | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/commitizen/cz/customize/customize.py b/commitizen/cz/customize/customize.py index e57caec11e..68cb990563 100644 --- a/commitizen/cz/customize/customize.py +++ b/commitizen/cz/customize/customize.py @@ -1,3 +1,5 @@ +from jinja2 import Template + from commitizen import defaults from commitizen.cz.base import BaseCommitizen @@ -24,8 +26,8 @@ def questions(self) -> list: return self.custom_config.get("questions") def message(self, answers: dict) -> str: - message_template = self.custom_config.get("message_template") - return message_template.format(**answers) + message_template = Template(self.custom_config.get("message_template")) + return message_template.render(**answers) def example(self) -> str: return self.custom_config.get("example") diff --git a/pyproject.toml b/pyproject.toml index c2bc24ddad..7392f11a5c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,6 +51,7 @@ colorama = "^0.4.1" termcolor = "^1.1" packaging = "^19.0" tomlkit = "^0.5.3" +jinja2 = "^2.10.3" [tool.poetry.dev-dependencies] ipython = "^7.2" diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py index ba034837c0..fa100987f3 100644 --- a/tests/test_cz_customize.py +++ b/tests/test_cz_customize.py @@ -11,7 +11,7 @@ def config(): toml_str = """ [tool.commitizen.customize] # message_template should follow the python string formatting spec - message_template = "{change_type}: {message}" + message_template = "{{change_type}}: {{message}}" example = "feature: this feature eanable customize through config file" schema = ": " bump_pattern = "^(break|new|fix|hotfix)" From c130d5ed100310ecf146729ec195d504c53e5be2 Mon Sep 17 00:00:00 2001 From: LeeW Date: Tue, 19 Nov 2019 11:03:38 -0500 Subject: [PATCH 4/7] test(cz/customize): add test example for jinja support #54 --- tests/test_cz_customize.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py index fa100987f3..6c1ea34d77 100644 --- a/tests/test_cz_customize.py +++ b/tests/test_cz_customize.py @@ -8,10 +8,10 @@ @pytest.fixture(scope="module") def config(): _conf = Config() - toml_str = """ + toml_str = r""" [tool.commitizen.customize] # message_template should follow the python string formatting spec - message_template = "{{change_type}}: {{message}}" + message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" example = "feature: this feature eanable customize through config file" schema = ": " bump_pattern = "^(break|new|fix|hotfix)" @@ -31,6 +31,11 @@ def config(): type = "input" name = "message" message = "Body." + + [[tool.commitizen.customize.questions]] + type = "confirm" + name = "show_message" + message = "Do you want to add body message in commit?" """ _conf.update(parse(toml_str)["tool"]["commitizen"]) return _conf.config @@ -65,6 +70,11 @@ def test_questions(config): "message": "Select the type of change you are committing", }, {"type": "input", "name": "message", "message": "Body."}, + { + "type": "confirm", + "name": "show_message", + "message": "Do you want to add body message in commit?", + }, ] assert list(questions) == expected_questions @@ -74,10 +84,20 @@ def test_answer(config): answers = { "change_type": "feature", "message": "this feature eanable customize through config file", + "show_message": True, } message = cz.message(answers) assert message == "feature: this feature eanable customize through config file" + cz = CustomizeCommitsCz(config) + answers = { + "change_type": "feature", + "message": "this feature eanable customize through config file", + "show_message": False, + } + message = cz.message(answers) + assert message == "feature:" + def test_example(config): cz = CustomizeCommitsCz(config) From d44ade8d0f78ca94b1e3b67dd40c760b09f202fb Mon Sep 17 00:00:00 2001 From: LeeW Date: Tue, 19 Nov 2019 11:11:35 -0500 Subject: [PATCH 5/7] docs(cz/customize): update doc for jinja support #54 --- docs/customization.md | 9 +++++++-- tests/test_cz_customize.py | 1 - 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/customization.md b/docs/customization.md index 5e0120f0b0..6adaaf5a34 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -151,7 +151,7 @@ Example: name = "cz_customize" [tool.commitizen.customize] -message_template = "{change_type}: {message}" +message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" example = "feature: this feature eanable customize through config file" schema = ": " bump_pattern = "^(break|new|fix|hotfix)" @@ -171,6 +171,11 @@ message = "Select the type of change you are committing" type = "input" name = "message" message = "Body." + +[[tool.commitizen.customize.questions]] +type = "confirm" +name = "show_message" +message = "Do you want to add body message in commit?" ``` ### Customize configuration @@ -178,7 +183,7 @@ message = "Body." | Parameter | Type | Default | Description | | --------- | ---- | ------- | ----------- | | `question` | `dict` | `None` | Questions regarding the commit message. Detatiled below. | -| `message_template` | `str` | `None` | The template for generating message from the given answers. `message_template` should follow the python string formatting specification, and all the variables in this template should be defined in `name` in `questions`. | +| `message_template` | `str` | `None` | The template for generating message from the given answers. `message_template` should follow the [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`. | | `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. | diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py index 6c1ea34d77..21fb1272e5 100644 --- a/tests/test_cz_customize.py +++ b/tests/test_cz_customize.py @@ -10,7 +10,6 @@ def config(): _conf = Config() toml_str = r""" [tool.commitizen.customize] - # message_template should follow the python string formatting spec message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" example = "feature: this feature eanable customize through config file" schema = ": " From aa7bc28b12885c98ae59e708526ab96a529134cf Mon Sep 17 00:00:00 2001 From: LeeW Date: Tue, 19 Nov 2019 13:53:17 -0500 Subject: [PATCH 6/7] refactor(cz/customize): make jinja2 a custom requirement. if not installed use string.Tempalte instead --- commitizen/cz/customize/customize.py | 10 ++++++++-- pyproject.toml | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/commitizen/cz/customize/customize.py b/commitizen/cz/customize/customize.py index 68cb990563..7120147763 100644 --- a/commitizen/cz/customize/customize.py +++ b/commitizen/cz/customize/customize.py @@ -1,4 +1,7 @@ -from jinja2 import Template +try: + from jinja2 import Template +except ImportError: + from string import Template from commitizen import defaults from commitizen.cz.base import BaseCommitizen @@ -27,7 +30,10 @@ def questions(self) -> list: def message(self, answers: dict) -> str: message_template = Template(self.custom_config.get("message_template")) - return message_template.render(**answers) + if getattr(Template, "substitute", None): + return message_template.substitute(**answers) + else: + return message_template.render(**answers) def example(self) -> str: return self.custom_config.get("example") diff --git a/pyproject.toml b/pyproject.toml index 7392f11a5c..bad79fe89f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,7 +51,7 @@ colorama = "^0.4.1" termcolor = "^1.1" packaging = "^19.0" tomlkit = "^0.5.3" -jinja2 = "^2.10.3" +jinja2 = {version = "^2.10.3", optional = true} [tool.poetry.dev-dependencies] ipython = "^7.2" From 0286e7bfff2666ea3f127da8bf3866b8f1faef92 Mon Sep 17 00:00:00 2001 From: LeeW Date: Tue, 19 Nov 2019 14:00:15 -0500 Subject: [PATCH 7/7] docs(cz/customize): update document for using string.Template as message_template when jinja not installed --- docs/customization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/customization.md b/docs/customization.md index 6adaaf5a34..9b6f990f84 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -183,7 +183,7 @@ message = "Do you want to add body message in commit?" | Parameter | Type | Default | Description | | --------- | ---- | ------- | ----------- | | `question` | `dict` | `None` | Questions regarding the commit message. Detatiled below. | -| `message_template` | `str` | `None` | The template for generating message from the given answers. `message_template` should follow the [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`. | +| `message_template` | `str` | `None` | The template for generating message from the given answers. `message_template` should either follow the [string.Template](https://docs.python.org/3/library/string.html#template-strings) or [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`. Note that `Jinja2` is not installed by default. If not installed, commitizen will use `string.Template` formatting. | | `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`. | | `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. |