From aa05bea3cf74a783ff3aecb5b9d18e2bb27afc5d Mon Sep 17 00:00:00 2001 From: Alan J Castonguay Date: Mon, 18 Nov 2019 08:10:51 -0500 Subject: [PATCH 0001/2044] feat: new 'git-cz' entrypoint Add 'git-cz' entrypoint in user's PATH. Project can now be invoked as 'git cz'. Fixes #60 --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 1b068f3156..c2bc24ddad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,6 +67,7 @@ isort = "^4.3.21" [tool.poetry.scripts] cz = "commitizen.cli:main" +git-cz = "commitizen.cli:main" [build-system] requires = ["poetry>=0.12"] From 746dd87314b422665094a590854aa6394c86ff5f Mon Sep 17 00:00:00 2001 From: LeeW Date: Mon, 18 Nov 2019 15:37:17 -0500 Subject: [PATCH 0002/2044] feat(cz/cz_customize): implement customizable cz #54 --- commitizen/cz/__init__.py | 7 ++- commitizen/cz/customize/__init__.py | 1 + commitizen/cz/customize/customize.py | 30 ++++++++++ commitizen/cz/customize/customize_info.txt | 0 scripts/test | 1 - tests/test_cz_customize.py | 65 ++++++++++++++++++++++ 6 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 commitizen/cz/customize/__init__.py create mode 100644 commitizen/cz/customize/customize.py create mode 100644 commitizen/cz/customize/customize_info.txt create mode 100644 tests/test_cz_customize.py diff --git a/commitizen/cz/__init__.py b/commitizen/cz/__init__.py index 88e936d0c6..5951b722d1 100644 --- a/commitizen/cz/__init__.py +++ b/commitizen/cz/__init__.py @@ -3,8 +3,13 @@ from commitizen.cz.conventional_commits import ConventionalCommitsCz from commitizen.cz.jira import JiraSmartCz +from commitizen.cz.customize import CustomizeCommitsCz -registry = {"cz_conventional_commits": ConventionalCommitsCz, "cz_jira": JiraSmartCz} +registry = { + "cz_conventional_commits": ConventionalCommitsCz, + "cz_jira": JiraSmartCz, + "cz_customize": CustomizeCommitsCz, +} plugins = { name: importlib.import_module(name).discover_this for finder, name, ispkg in pkgutil.iter_modules() diff --git a/commitizen/cz/customize/__init__.py b/commitizen/cz/customize/__init__.py new file mode 100644 index 0000000000..c5af001a79 --- /dev/null +++ b/commitizen/cz/customize/__init__.py @@ -0,0 +1 @@ +from .customize import CustomizeCommitsCz # noqa diff --git a/commitizen/cz/customize/customize.py b/commitizen/cz/customize/customize.py new file mode 100644 index 0000000000..ec3bc1ef48 --- /dev/null +++ b/commitizen/cz/customize/customize.py @@ -0,0 +1,30 @@ +from commitizen import defaults +from commitizen.cz.base import BaseCommitizen + +__all__ = ["CustomizeCommitsCz"] + + +class CustomizeCommitsCz(BaseCommitizen): + bump_pattern = defaults.bump_pattern + bump_map = defaults.bump_map + + def __init__(self, config: dict): + super(CustomizeCommitsCz, self).__init__(config) + self.custom_config = self.config.get("customize") + + 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) + + def example(self) -> str: + return self.custom_config.get("example") + + def schema(self) -> str: + return self.custom_config.get("schema") + + def info(self) -> str: + # TODO + raise NotImplementedError("Not Implemented yet") diff --git a/commitizen/cz/customize/customize_info.txt b/commitizen/cz/customize/customize_info.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/scripts/test b/scripts/test index 2234ddc65c..78753c7703 100755 --- a/scripts/test +++ b/scripts/test @@ -1,4 +1,3 @@ -export PREFIX="poetry run python -m " if [ -d 'venv' ] ; then export PREFIX="venv/bin/" fi diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py new file mode 100644 index 0000000000..733f5fc823 --- /dev/null +++ b/tests/test_cz_customize.py @@ -0,0 +1,65 @@ +import pytest +from tomlkit import parse + +from commitizen.cz.customize import CustomizeCommitsCz +from commitizen.config import Config + + +@pytest.fixture(scope="module") +def config(): + _conf = Config() + toml_str = """ + [tool.commitizen.customize] + # message_template should follow the python string formatting spec + message_template = "{change_type}: {message}" + example = "feature: this feature eanable customize through config file" + schema = ": " + + [[tool.commitizen.customize.questions]] + type = "list" + name = "change_type" + choices = ["feature", "bug fix"] + message = "Select the type of change you are committing" + + [[tool.commitizen.customize.questions]] + type = "input" + name = "message" + message = "Body." + """ + _conf.update(parse(toml_str)["tool"]["commitizen"]) + return _conf.config + + +def test_questions(config): + cz = CustomizeCommitsCz(config) + questions = cz.questions() + expected_questions = [ + { + "type": "list", + "name": "change_type", + "choices": ["feature", "bug fix"], + "message": "Select the type of change you are committing", + }, + {"type": "input", "name": "message", "message": "Body."}, + ] + assert list(questions) == expected_questions + + +def test_answer(config): + cz = CustomizeCommitsCz(config) + answers = { + "change_type": "feature", + "message": "this feature eanable customize through config file", + } + message = cz.message(answers) + assert message == "feature: this feature eanable customize through config file" + + +def test_example(config): + cz = CustomizeCommitsCz(config) + assert "feature: this feature eanable customize through config file" in cz.example() + + +def test_schema(config): + cz = CustomizeCommitsCz(config) + assert ": " in cz.schema() From 78aa985f24765b7d44f1f708bbd0a9b7dc51df0a Mon Sep 17 00:00:00 2001 From: LeeW Date: Mon, 18 Nov 2019 15:53:16 -0500 Subject: [PATCH 0003/2044] feat(cz/cz_customize): enable bump_pattern bump_map customization --- commitizen/cz/customize/customize.py | 8 ++++++++ tests/test_cz_customize.py | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/commitizen/cz/customize/customize.py b/commitizen/cz/customize/customize.py index ec3bc1ef48..f432a53567 100644 --- a/commitizen/cz/customize/customize.py +++ b/commitizen/cz/customize/customize.py @@ -12,6 +12,14 @@ def __init__(self, config: dict): super(CustomizeCommitsCz, self).__init__(config) self.custom_config = self.config.get("customize") + custom_bump_pattern = self.custom_config.get("bump_pattern") + if custom_bump_pattern: + self.bump_pattern = custom_bump_pattern + + custom_bump_map = self.custom_config.get("bump_map") + if custom_bump_map: + self.bump_map = custom_bump_map + def questions(self) -> list: return self.custom_config.get("questions") diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py index 733f5fc823..4812ebb3e1 100644 --- a/tests/test_cz_customize.py +++ b/tests/test_cz_customize.py @@ -14,6 +14,8 @@ def config(): message_template = "{change_type}: {message}" example = "feature: this feature eanable customize through config file" schema = ": " + bump_pattern = "^(break|new|fix|hotfix)" + bump_map = {"break" = "MAJOR", "new" = "MINOR", "fix" = "PATCH", "hotfix" = "PATCH"} [[tool.commitizen.customize.questions]] type = "list" @@ -30,6 +32,21 @@ def config(): return _conf.config +def test_bump_pattern(config): + cz = CustomizeCommitsCz(config) + assert cz.bump_pattern == "^(break|new|fix|hotfix)" + + +def test_bump_map(config): + cz = CustomizeCommitsCz(config) + assert cz.bump_map == { + "break": "MAJOR", + "new": "MINOR", + "fix": "PATCH", + "hotfix": "PATCH", + } + + def test_questions(config): cz = CustomizeCommitsCz(config) questions = cz.questions() From 088e24f531feaee1be9f2ac5371dab61dc304e1c Mon Sep 17 00:00:00 2001 From: LeeW Date: Mon, 18 Nov 2019 16:10:00 -0500 Subject: [PATCH 0004/2044] feat(cz/cz_customize): implement info to support info and info_path #54 --- commitizen/cz/customize/customize.py | 9 ++++++++- tests/test_cz_customize.py | 6 ++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/commitizen/cz/customize/customize.py b/commitizen/cz/customize/customize.py index f432a53567..e57caec11e 100644 --- a/commitizen/cz/customize/customize.py +++ b/commitizen/cz/customize/customize.py @@ -34,5 +34,12 @@ def schema(self) -> str: return self.custom_config.get("schema") def info(self) -> str: - # TODO + info_path = self.custom_config.get("info_path") + info = self.custom_config.get("info") + if info_path: + with open(info_path, "r") as f: + content = f.read() + return content + elif info: + return info raise NotImplementedError("Not Implemented yet") diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py index 4812ebb3e1..57956fb100 100644 --- a/tests/test_cz_customize.py +++ b/tests/test_cz_customize.py @@ -16,6 +16,7 @@ def config(): schema = ": " bump_pattern = "^(break|new|fix|hotfix)" bump_map = {"break" = "MAJOR", "new" = "MINOR", "fix" = "PATCH", "hotfix" = "PATCH"} + info = "This is a customized cz." [[tool.commitizen.customize.questions]] type = "list" @@ -80,3 +81,8 @@ def test_example(config): def test_schema(config): cz = CustomizeCommitsCz(config) assert ": " in cz.schema() + + +def test_info(config): + cz = CustomizeCommitsCz(config) + assert "This is a customized cz." in cz.info() From c1f323564330d5a28867816f0730c1c1b966c466 Mon Sep 17 00:00:00 2001 From: LeeW Date: Mon, 18 Nov 2019 16:56:06 -0500 Subject: [PATCH 0005/2044] test(cz/cz_customize): Change the value for choices #54 --- tests/test_cz_customize.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py index 57956fb100..ba034837c0 100644 --- a/tests/test_cz_customize.py +++ b/tests/test_cz_customize.py @@ -21,7 +21,10 @@ def config(): [[tool.commitizen.customize.questions]] type = "list" name = "change_type" - choices = ["feature", "bug fix"] + choices = [ + {value = "feature", name = "feature: A new feature."}, + {value = "bug fix", name = "bug fix: A bug fix."} + ] message = "Select the type of change you are committing" [[tool.commitizen.customize.questions]] @@ -55,7 +58,10 @@ def test_questions(config): { "type": "list", "name": "change_type", - "choices": ["feature", "bug fix"], + "choices": [ + {"value": "feature", "name": "feature: A new feature."}, + {"value": "bug fix", "name": "bug fix: A bug fix."}, + ], "message": "Select the type of change you are committing", }, {"type": "input", "name": "message", "message": "Body."}, From f863eaef1e473f83e6e80941eec5a6e66137e273 Mon Sep 17 00:00:00 2001 From: LeeW Date: Mon, 18 Nov 2019 17:00:32 -0500 Subject: [PATCH 0006/2044] docs(cz/cz_customize): description for newly added customization functionality #54 --- docs/config.md | 1 + docs/customization.md | 69 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/docs/config.md b/docs/config.md index dcbb218e86..e4852de2b3 100644 --- a/docs/config.md +++ b/docs/config.md @@ -65,3 +65,4 @@ The extra tab before the square brakets (`]`) at the end is required. | `tag_format` | `str` | `None` | Format for the git tag, useful for old projects, that use a convention like `"v1.2.1"`. [See more](https://woile.github.io/commitizen/bump#tag_format) | | `bump_message` | `str` | `None` | Create custom commit message, useful to skip ci. [See more](https://woile.github.io/commitizen/bump#bump_message) | | `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://woile.github.io/commitizen/customization/) | diff --git a/docs/customization.md b/docs/customization.md index f863d9fae3..5e0120f0b0 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -1,5 +1,7 @@ Customizing commitizen is not hard at all. +## Customize through customize class + The basic steps are: 1. Inheriting from `BaseCommitizen` @@ -9,7 +11,7 @@ The basic steps are: Check an [example](convcomms) on how to configure `BaseCommitizen`. -## Custom commit rules +### Custom commit rules Create a file starting with `cz_` for example `cz_jira.py`. This prefix is used to detect the plugin. Same method [flask uses] @@ -95,7 +97,7 @@ If you feel like it should be part of this repo, create a PR. [flask uses]: http://flask.pocoo.org/docs/0.12/extensiondev/ -## Custom bump rules +### Custom bump rules You need to define 2 parameters inside `BaseCommitizen`. @@ -123,7 +125,7 @@ cz -n cz_strange bump [convcomms]: https://github.com/Woile/commitizen/blob/master/commitizen/cz/conventional_commits/conventional_commits.py -## Raise Customize Exception +### Raise Customize Exception If you wannt `commitizen` to catch your exception and print the message, you'll have to inherit `CzException`. @@ -133,3 +135,64 @@ from commitizen.cz.exception import CzException class NoSubjectProvidedException(CzException): ... ``` + +## Customize in toml + +**This is only supported when configuring through `toml` (e.g., `pyproject.toml`, `.cz`, and `.cz.toml`)** + +The basic steps are: +1. Define your custom committing or bumpping rules in the configuration file. +2. Declare `name = "cz_customize"` in your configuration file, or add `-n cz_customize` when running commitizen. + +Example: + +```toml +[tool.commitizen] +name = "cz_customize" + +[tool.commitizen.customize] +message_template = "{change_type}: {message}" +example = "feature: this feature eanable customize through config file" +schema = ": " +bump_pattern = "^(break|new|fix|hotfix)" +bump_map = {"break" = "MAJOR", "new" = "MINOR", "fix" = "PATCH", "hotfix" = "PATCH"} +info_path = "cz_customize_info.txt" +info = """ +This is customized info +""" + +[[tool.commitizen.customize.questions]] +type = "list" +name = "change_type" +choices = ["feature", "bug fix"] +message = "Select the type of change you are committing" + +[[tool.commitizen.customize.questions]] +type = "input" +name = "message" +message = "Body." +``` + +### Customize configuration + +| 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`. | +| `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. | +| `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) | + +#### Detailed `question` 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 = choice`. It should be list of dictionaries with `name` and `value`. (e.g., `[{value = "feature", name = "feature: A new feature."}, {value = "bug fix", name = "bug fix: A bug fix."}]`) | +| `default` | `Any` | `None` | (OPTIONAL) The default value for this question. | +| `filter` | `str` | `None` | (Optional) Validator for user's answer. **(Work in Progress)** | From e4c93d0fa5624e4d5d1171f5dce6e4efa489aa3e Mon Sep 17 00:00:00 2001 From: LeeW Date: Mon, 18 Nov 2019 17:08:29 -0500 Subject: [PATCH 0007/2044] fix(scripts): add back the delelte poetry prefix #54 --- scripts/test | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/test b/scripts/test index 78753c7703..2234ddc65c 100755 --- a/scripts/test +++ b/scripts/test @@ -1,3 +1,4 @@ +export PREFIX="poetry run python -m " if [ -d 'venv' ] ; then export PREFIX="venv/bin/" fi From 1d5507d48730ad5fd69419caac6d5ac7193349b7 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Tue, 19 Nov 2019 03:33:54 -0500 Subject: [PATCH 0008/2044] fix: removing folder in windows throwing a PermissionError * #issue67 created handler for readonly files/dirs to be passed to shutil.rmtree(). will change permissions and retry operation if readonly dir/file found. * added reference for where handler code came from * prettied report of c.err * created exception to raise if unable to change permission in handler * tidy error report * correcting style mistakes Closes #67 --- commitizen/commands/bump.py | 2 +- tests/test_bump_command.py | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 5b30caf4ff..89cec1153a 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(c.err) + 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/tests/test_bump_command.py b/tests/test_bump_command.py index 861057d46d..f39668145c 100644 --- a/tests/test_bump_command.py +++ b/tests/test_bump_command.py @@ -1,5 +1,7 @@ import os import shutil +import stat +import errno import sys import uuid from pathlib import Path @@ -10,6 +12,20 @@ from commitizen import cli, cmd, git +def ReadOnlyException(Exception): + pass + + +# https://stackoverflow.com/questions/1213706/what-user-do-python-scripts-run-as-in-windows +def handleRemoveReadOnly(func, path, exc): + excvalue = exc[1] + if func in (os.rmdir, os.remove, shutil.rmtree) and excvalue.errno == errno.EACCESS: + os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.IRWXO) # 744 + func(path) + else: + raise ReadOnlyException + + @pytest.fixture def create_project(): current_directory = os.getcwd() @@ -20,7 +36,7 @@ def create_project(): os.chdir(full_tmp_path) yield os.chdir(current_directory) - shutil.rmtree(full_tmp_path) + shutil.rmtree(full_tmp_path, handleRemoveReadOnly) def create_file_and_commit(message: str, filename: Optional[str] = None): From d4c40d8bb0741f6338d79d7ef959d5e2f9cd7654 Mon Sep 17 00:00:00 2001 From: R Lin <44857095+modlin@users.noreply.github.com> Date: Tue, 19 Nov 2019 03:49:36 -0500 Subject: [PATCH 0009/2044] fix: correct typo to spell "convention" Fixes #70. --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index acedde15fd..ce87492366 100644 --- a/README.rst +++ b/README.rst @@ -49,7 +49,7 @@ and communicating it (using the cli provided by commitizen). The reasoning behind it is that is easier to read, and enforces writing descriptive commits. -Besides that, having a convetion on your commits, makes it possible to +Besides that, having a convention on your commits, makes it possible to parse them and use them for something else, like generating automatically the version or a changelog. @@ -179,4 +179,4 @@ Feel free to create a PR. 4. Run :code:`./scripts/test` -.. _conventional commits: https://conventionalcommits.org/ \ No newline at end of file +.. _conventional commits: https://conventionalcommits.org/ From e0675b31ade7fb206514e76654a3789fd5bb1361 Mon Sep 17 00:00:00 2001 From: Daniel Vergara Date: Mon, 18 Nov 2019 14:07:09 -0600 Subject: [PATCH 0010/2044] =?UTF-8?q?feat(Commands/commit):=20add=20=C2=B4?= =?UTF-8?q?--dry-run=C2=B4=20flag=20to=20the=20Commit=20command?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Generate a commit message without doing anything closes #56 --- commitizen/cli.py | 7 ++++++- commitizen/commands/commit.py | 6 ++++++ tests/test_commands.py | 17 +++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index 620707c588..805e1fb3d3 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -45,7 +45,12 @@ "name": ["--retry"], "action": "store_true", "help": "retry last commit", - } + }, + { + "name": "--dry-run", + "action": "store_true", + "help": "show output to stdout, no commit, no modified files", + }, ], }, { diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index 8b438da4d7..c67a381f18 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -63,6 +63,12 @@ def __call__(self): m = self.prompt_commit_questions() out.info(f"\n{m}\n") + + dry_run: bool = self.arguments.get("dry_run") + + if dry_run: + raise SystemExit(NOTHING_TO_COMMIT) + c = git.commit(m) if c.err: diff --git a/tests/test_commands.py b/tests/test_commands.py index bd08c3da8f..3206d28002 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -82,6 +82,23 @@ def test_commit_retry_works(mocker): assert not os.path.isfile(temp_file) +@pytest.mark.usefixtures("staging_is_clean") +def test_commit_command_with_dry_run_option(mocker): + prompt_mock = mocker = mocker.patch("questionary.prompt") + prompt_mock.return_value = { + "prefix": "feat", + "subject": "user created", + "scope": "", + "is_breaking_change": False, + "body": "closes #57", + "footer": "", + } + + with pytest.raises(SystemExit): + commit_cmd = commands.Commit(config, {"dry_run": True}) + commit_cmd() + + def test_commit_when_nothing_to_commit(mocker): is_staging_clean_mock = mocker.patch("commitizen.git.is_staging_clean") is_staging_clean_mock.return_value = True From 425197ad58111513ea386ffce135f293fc3e99c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= Date: Tue, 19 Nov 2019 19:06:21 +0100 Subject: [PATCH 0011/2044] fix: commit dry-run doesnt require staging to be clean --- commitizen/commands/commit.py | 6 +++--- tests/test_commands.py | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index c67a381f18..d67fe31c8c 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -51,7 +51,9 @@ def prompt_commit_questions(self) -> str: return cz.message(answers) def __call__(self): - if git.is_staging_clean(): + dry_run: bool = self.arguments.get("dry_run") + + if git.is_staging_clean() and not dry_run: out.write("No files added to staging!") raise SystemExit(NOTHING_TO_COMMIT) @@ -64,8 +66,6 @@ def __call__(self): out.info(f"\n{m}\n") - dry_run: bool = self.arguments.get("dry_run") - if dry_run: raise SystemExit(NOTHING_TO_COMMIT) diff --git a/tests/test_commands.py b/tests/test_commands.py index 3206d28002..dc2cfe0b0d 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -110,11 +110,10 @@ def test_commit_when_nothing_to_commit(mocker): assert err.value.code == commands.commit.NOTHING_TO_COMMIT +@pytest.mark.usefixtures("staging_is_clean") def test_commit_when_customized_expected_raised(mocker, capsys): _err = ValueError() _err.__context__ = CzException("This is the root custom err") - git_mock = mocker.patch("commitizen.git.is_staging_clean") - git_mock.return_value = False prompt_mock = mocker.patch("questionary.prompt") prompt_mock.side_effect = _err From d968daf1271e3cb1126be1eb62939a2b41badbf0 Mon Sep 17 00:00:00 2001 From: LeeW Date: Tue, 19 Nov 2019 10:50:33 -0500 Subject: [PATCH 0012/2044] 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 0013/2044] 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 0014/2044] 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 0015/2044] 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 0016/2044] 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 0017/2044] 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 0018/2044] 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. | From 47c7ce8ffb8a69f7af5d1d40c477234c4ad201d4 Mon Sep 17 00:00:00 2001 From: LeeW Date: Tue, 19 Nov 2019 14:25:38 -0500 Subject: [PATCH 0019/2044] feat(config): add deprecation warning for loading config from ini files #55 --- commitizen/config.py | 4 ++++ commitizen/defaults.py | 3 ++- docs/config.md | 6 ++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/commitizen/config.py b/commitizen/config.py index 24507e0ea9..eb0102c3d9 100644 --- a/commitizen/config.py +++ b/commitizen/config.py @@ -121,6 +121,10 @@ def read_cfg() -> dict: if "toml" in filename: conf = read_pyproject_conf(data) else: + warnings.warn( + ".cz, setup.cfg, and .cz.cgf will be deprecated in next major version. \n" + 'Please use "pyproject.toml", ".cz.toml" instead' + ) conf = read_raw_parser_conf(data) if not conf: continue diff --git a/commitizen/defaults.py b/commitizen/defaults.py index d6287fe67c..e63167d0e5 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -1,5 +1,6 @@ name: str = "cz_conventional_commits" -config_files: list = ["pyproject.toml", ".cz", "setup.cfg", ".cz.cfg"] +# TODO: .cz, setup.cfg, .cz.cfg should be removed in 2.0 +config_files: list = ["pyproject.toml", ".cz.toml", ".cz", "setup.cfg", ".cz.cfg"] # Available settings settings: dict = { diff --git a/docs/config.md b/docs/config.md index e4852de2b3..229e1a86a5 100644 --- a/docs/config.md +++ b/docs/config.md @@ -2,9 +2,9 @@ Commitizen has support for `toml` and `ini` files. -## pyproject.toml +## pyproject.toml or .cz.toml -Add an entry to `pyproject.toml`. Recommended for **python** projects. +Add an entry to `pyproject.toml or .cz.toml`. Recommended for **python** projects. [tool.commitizen] name = "cz_conventional_commits" @@ -28,6 +28,8 @@ Add an entry to `pyproject.toml`. Recommended for **python** projects. ## INI files +**INI files will not be supported in next major version. Please use toml instead** + Supported files: `.cz`, `.cz.cfg`, `setup.py`, and `$HOME/.cz` The format is slightly different to the `toml`, so pay attention. From f153019c4f130f543d2c69134f1327d6c9f1c2a4 Mon Sep 17 00:00:00 2001 From: LeeW Date: Tue, 19 Nov 2019 14:27:40 -0500 Subject: [PATCH 0020/2044] refactor(config): remove has_pyproject which is no longer used --- commitizen/commands/bump.py | 2 +- commitizen/config.py | 7 ++----- tests/test_conf.py | 10 ---------- 3 files changed, 3 insertions(+), 16 deletions(-) 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/config.py b/commitizen/config.py index eb0102c3d9..b611d34a6f 100644 --- a/commitizen/config.py +++ b/commitizen/config.py @@ -33,10 +33,6 @@ def add_path(self, path: str): _conf = Config() -def has_pyproject() -> bool: - return os.path.isfile("pyproject.toml") - - def read_pyproject_conf(data: str) -> dict: """We expect to have a section in pyproject looking like @@ -122,7 +118,8 @@ def read_cfg() -> dict: conf = read_pyproject_conf(data) else: warnings.warn( - ".cz, setup.cfg, and .cz.cgf will be deprecated in next major version. \n" + ".cz, setup.cfg, and .cz.cgf will be deprecated " + "in next major version. \n" 'Please use "pyproject.toml", ".cz.toml" instead' ) conf = read_raw_parser_conf(data) diff --git a/tests/test_conf.py b/tests/test_conf.py index 2544bd5c2d..3a94834161 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -99,16 +99,6 @@ def empty_pyproject_ok_cz(): os.remove(cz) -def test_no_pyproject(mocker): - with mocker.patch("os.path.isfile", return_value=False): - assert config.has_pyproject() is False - - -def test_has_pyproject(mocker): - with mocker.patch("os.path.isfile", return_value=True): - assert config.has_pyproject() is True - - def test_read_pyproject_conf(): assert config.read_pyproject_conf(PYPROJECT) == _read_conf From 221f5285f5b2799d08d418c631c348120dfdebc6 Mon Sep 17 00:00:00 2001 From: Daniel Vergara Date: Tue, 19 Nov 2019 15:04:54 -0600 Subject: [PATCH 0021/2044] feat(Commands/check): enforce the project to always use conventional commits closes #59 --- README.rst | 3 +- commitizen/cli.py | 15 +++++++++ commitizen/commands/__init__.py | 4 ++- commitizen/commands/check.py | 52 +++++++++++++++++++++++++++++++ tests/test_commands.py | 55 +++++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 commitizen/commands/check.py diff --git a/README.rst b/README.rst index ce87492366..c9cae65df3 100644 --- a/README.rst +++ b/README.rst @@ -160,13 +160,14 @@ Usage --version get the version of the installed commitizen commands: - {ls,commit,c,example,info,schema,bump} + {ls,commit,c,example,info,schema,bump,check} ls show available commitizens commit (c) create new commit example show commit example info show information about the cz schema show commit schema bump bump semantic version based on the git log + check enforce the project to always use conventional commits Contributing ============ diff --git a/commitizen/cli.py b/commitizen/cli.py index 805e1fb3d3..be6103226a 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -111,6 +111,21 @@ "help": "get the version of the installed commitizen", "func": commands.Version, }, + { + "name": ["check"], + "help": "enforce the project to always use conventional commits", + "func": commands.Check, + "arguments": [ + { + "name": "--commit-msg-file", + "help": ( + "ask for the name of the temporal file that contains " + "the commit message. " + "Using it in a git hook script: MSG_FILE=$1" + ), + } + ], + }, ], }, } diff --git a/commitizen/commands/__init__.py b/commitizen/commands/__init__.py index 644356a759..ea17a8a5f3 100644 --- a/commitizen/commands/__init__.py +++ b/commitizen/commands/__init__.py @@ -1,9 +1,11 @@ from .bump import Bump from .commit import Commit +from .check import Check from .example import Example from .info import Info from .list_cz import ListCz from .schema import Schema from .version import Version -__all__ = ("Bump", "Commit", "Example", "Info", "ListCz", "Schema", "Version") +__all__ = ("Bump", "Check", "Commit", "Example", "Info", "ListCz", "Schema", + "Version") diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py new file mode 100644 index 0000000000..67a449a03d --- /dev/null +++ b/commitizen/commands/check.py @@ -0,0 +1,52 @@ +import os +import re + +from commitizen import out + +PATTERN = (r'(build|ci|docs|feat|fix|perf|refactor|style|test|chore|revert)' + r'(\([\w\-]+\))?:\s.*') +NO_COMMIT_MSG = 3 +INVALID_COMMIT_MSG = 5 + + +class Check: + """Check if the current commit msg is a conventional commit.""" + + def __init__(self, config: dict, arguments: dict, cwd=os.getcwd()): + """Init method. + + Parameters + ---------- + config : dict + the config object required for the command to perform its action + arguments : dict + the arguments object that contains all + the flags provided by the user + + """ + self.config: dict = config + self.arguments: dict = arguments + + def __call__(self): + """Validate if a commit message follows the conventional pattern. + + Raises + ------ + SystemExit + if the commit provided not follows the conventional pattern + + """ + commit_msg_content = self._get_commit_msg() + if self._is_conventional(PATTERN, commit_msg_content) is not None: + out.success("Conventional commit validation: successful!") + else: + out.error("conventional commit validation: failed!") + out.error("please enter a commit message in the conventional format.") + raise SystemExit(INVALID_COMMIT_MSG) + + def _get_commit_msg(self): + temp_filename: str = self.arguments.get("commit_msg_file") + return open(temp_filename, 'r').read() + + def _is_conventional(self, pattern, commit_msg): + return re.match(PATTERN, commit_msg) diff --git a/tests/test_commands.py b/tests/test_commands.py index dc2cfe0b0d..210e392352 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -1,4 +1,7 @@ +import contextlib import os +import shutil +import tempfile from unittest import mock import pytest @@ -15,6 +18,15 @@ def staging_is_clean(mocker): is_staging_clean_mock.return_value = False +@contextlib.contextmanager +def get_temp_dir(): + temp_dir = tempfile.mkdtemp() + try: + yield temp_dir + finally: + shutil.rmtree(temp_dir) + + @pytest.mark.usefixtures("staging_is_clean") def test_commit(mocker): prompt_mock = mocker.patch("questionary.prompt") @@ -158,3 +170,46 @@ def test_version(): commands.Version(config)() mocked_write.assert_called_once() + + +def test_check_no_conventional_commit(mocker): + with pytest.raises(SystemExit): + error_mock = mocker.patch("commitizen.out.error") + + with get_temp_dir() as dir: + + tempfile = os.path.join(dir, "temp_commit_file") + with open(tempfile, 'w') as f: + f.write("no conventional commit") + + check_cmd = commands.Check( + config=config, + arguments={"commit_msg_file": tempfile} + ) + check_cmd() + error_mock.assert_called_once() + + +def test_check_conventional_commit(mocker): + success_mock = mocker.patch("commitizen.out.success") + with get_temp_dir() as dir: + + tempfile = os.path.join(dir, "temp_commit_file") + with open(tempfile, 'w') as f: + f.write("feat(lang): added polish language") + + check_cmd = commands.Check( + config=config, + arguments={"commit_msg_file": tempfile} + ) + + check_cmd() + success_mock.assert_called_once() + + +def test_check_command_when_commit_file_not_found(): + with pytest.raises(FileNotFoundError): + commands.Check( + config=config, + arguments={"commit_msg_file": ""} + )() From 5bac64bdca6a73d43510dd709da835461ec72750 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Wed, 20 Nov 2019 04:13:36 -0500 Subject: [PATCH 0022/2044] style: correcting style mistake From dd8b974c2c87986b340b34cf4a8d2eacec7df233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= Date: Wed, 20 Nov 2019 10:39:42 +0100 Subject: [PATCH 0023/2044] docs(CHANGELOG): added unreleased information --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a248316d0d..a3f2cbdaec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # CHANGELOG +## Unreleased + +### Feature + +- new `version` command. `--version` will be deprecated in `2.0.0` +- new `git-cz` entrypoint. After installing `commitizen` you can run `git cz c` (#60) +- new `--dry-run` argument in `commit` (#56) +- new `cz check` command which checks if the message is valid with the rules (#59). Useful for git hooks. +- create a commiting rule directly in the config file (#54) +- support for multi-line body (#6) +- support for jinja templates. Install doign `pip install -U commitizen[jinja2]`. +- support for `.cz.toml`. The confs depending on `ConfigParser` will be deprecated in `2.0.0`. + + +### Fix + +- tests were fixed +- windows error when removing folders (#67) +- typos in docs + ## v1.8.0 ### Feature From 82ae6fd8d63a4ada7c52fbabb57d5b014f3a400b Mon Sep 17 00:00:00 2001 From: marcosschroh Date: Wed, 20 Nov 2019 12:42:18 +0100 Subject: [PATCH 0024/2044] docs(Tutorial): Tutorial section added. GitLab tutorial added --- docs/images/gitlab_ci/gitlab_deploy_key.png | Bin 0 -> 65165 bytes .../gitlab_ci/gitlab_final_ci_result.png | Bin 0 -> 32867 bytes docs/images/gitlab_ci/gitlab_variables.png | Bin 0 -> 87870 bytes docs/tutorials/gitlab_ci.md | 114 ++++++++++++++++++ mkdocs.yml | 2 + 5 files changed, 116 insertions(+) create mode 100644 docs/images/gitlab_ci/gitlab_deploy_key.png create mode 100644 docs/images/gitlab_ci/gitlab_final_ci_result.png create mode 100644 docs/images/gitlab_ci/gitlab_variables.png create mode 100644 docs/tutorials/gitlab_ci.md diff --git a/docs/images/gitlab_ci/gitlab_deploy_key.png b/docs/images/gitlab_ci/gitlab_deploy_key.png new file mode 100644 index 0000000000000000000000000000000000000000..dd70443c326ab07338dbe6b426061981d85d4c80 GIT binary patch literal 65165 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 U*d-u>hWb-i1*sI=fARLe0JD+ISpWb4 literal 0 HcmV?d00001 diff --git a/docs/images/gitlab_ci/gitlab_final_ci_result.png b/docs/images/gitlab_ci/gitlab_final_ci_result.png new file mode 100644 index 0000000000000000000000000000000000000000..27749db793a3cfa2abf44c40469ae1a4687a9fbb GIT binary patch literal 32867 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 O`V$wH5vmf@^ZP%>OOew6 literal 0 HcmV?d00001 diff --git a/docs/images/gitlab_ci/gitlab_variables.png b/docs/images/gitlab_ci/gitlab_variables.png new file mode 100644 index 0000000000000000000000000000000000000000..d00ebfcf7912796a6c9584b19ae852b51ea0bffc GIT binary patch literal 87870 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 z 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 n62i;M5e=h1@X~@E3XJ}_jjnywuCnh1 /dev/null # add ssh key + - pip3 install -U Commitizen # install commitizen + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - echo "$SSH_PUBLIC_KEY" >> ~/.ssh/id_rsa.pub + - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config' + dependencies: + - test + script: + - git remote set-url origin git@gitlab.com:discover/rentee-core.git # git configuration + - git config --global user.email "${CI_EMAIL}" && git config --global user.name "${CI_USERNAME}" + - 'exists=`git show-ref refs/heads/master` && if [ -n "$exists" ]; then git branch -D master; fi' + - git checkout -b master + - cz bump # execute auto bump and push to master + - git push origin master:$CI_COMMIT_REF_NAME + - TAG=$(head -n 1 VERSION) # get the new software version and save into artifacts + - echo "#!/bin/sh" >> variables + - echo "export TAG='$TAG'" >> variables + - git push origin $TAG + only: + refs: + - master + artifacts: + paths: + - variables +``` + +So, every time that a developer push to any branch the `test` job is executed. If the branch is `master` and the test jobs success, the `auto-bump` takes place. +To be able to push using the Gitlab runner we have to set the ssh key, configure git and finally execute the auto bump. + +After merging the new changed into master we have the final result: + +![gitlab final ci result](../images/gitlab_ci/gitlab_final_ci_result.png) diff --git a/mkdocs.yml b/mkdocs.yml index 699e06b196..13921fe0c5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -13,6 +13,8 @@ nav: - Configuration: 'config.md' - Bump: 'bump.md' - Customization: 'customization.md' + - Tutorials: + - GitLab CI: 'tutorials/gitlab_ci.md' markdown_extensions: - markdown.extensions.codehilite: From c96fd8d0c3b51b6b8414f1b9651b9ba19a4c39d9 Mon Sep 17 00:00:00 2001 From: santiago fraire Date: Fri, 22 Nov 2019 19:10:03 +0100 Subject: [PATCH 0025/2044] ci: new bump and publish github actions --- .github/workflows/bumpversion.yml | 37 ++++++++++++++++++++++++++++ .github/workflows/pythonpublish.yaml | 27 ++++++++++++++++++++ scripts/deploy | 5 ---- scripts/publish | 12 +++++++++ 4 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/bumpversion.yml create mode 100644 .github/workflows/pythonpublish.yaml delete mode 100755 scripts/deploy create mode 100755 scripts/publish diff --git a/.github/workflows/bumpversion.yml b/.github/workflows/bumpversion.yml new file mode 100644 index 0000000000..d8fcb18213 --- /dev/null +++ b/.github/workflows/bumpversion.yml @@ -0,0 +1,37 @@ +name: Bump version + +on: + push: + branches: + - master + +jobs: + build: + if: "!contains(github.event.head_commit.message, 'bump')" + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['3.x'] + steps: + - uses: actions/checkout@master + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python --version + python --version + python -m pip install -U commitizen + - name: Create bump + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git config --local push.followTags true + cz bump --yes + git tag + - name: Push changes + uses: Woile/github-push-action@master + with: + github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + tags: "true" diff --git a/.github/workflows/pythonpublish.yaml b/.github/workflows/pythonpublish.yaml new file mode 100644 index 0000000000..bf61909073 --- /dev/null +++ b/.github/workflows/pythonpublish.yaml @@ -0,0 +1,27 @@ +name: Upload Python Package + +on: + push: + tags: + - 'v*' + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Set up Python + uses: actions/setup-python@v1 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --pre -U poetry + poetry --version + poetry install + - name: Build and publish + env: + PYPI_USERNAME: ${{ secrets.PYPI_USERNAME }} + PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + run: | + ./scripts/publish diff --git a/scripts/deploy b/scripts/deploy deleted file mode 100755 index 52c914c71a..0000000000 --- a/scripts/deploy +++ /dev/null @@ -1,5 +0,0 @@ -# Publish to pypi -poetry publish --build - -# Publish docs -mkdocs gh-deploy diff --git a/scripts/publish b/scripts/publish new file mode 100755 index 0000000000..ec97859484 --- /dev/null +++ b/scripts/publish @@ -0,0 +1,12 @@ +# Publish to pypi +poetry publish --build -u $PYPI_USERNAME -p $PYPI_PASSWORD + +[ -z "${INPUT_GITHUB_TOKEN}" ] && { + echo 'Missing input "github_token: ${{ secrets.GITHUB_TOKEN }}".'; + exit 1; +}; + +remote_repo="https://${GITHUB_ACTOR}:${INPUT_GITHUB_TOKEN}@github.com/commitizen.git" + +# Publish docs +mkdocs gh-deploy --remote-name "${remote_repo}" From 1217216950a92099196fe025f360cc7964c812a5 Mon Sep 17 00:00:00 2001 From: santiago fraire Date: Fri, 22 Nov 2019 19:32:05 +0100 Subject: [PATCH 0026/2044] docs: github actions tutorial --- docs/tutorials/github_actions.md | 99 ++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 docs/tutorials/github_actions.md diff --git a/docs/tutorials/github_actions.md b/docs/tutorials/github_actions.md new file mode 100644 index 0000000000..04bc976664 --- /dev/null +++ b/docs/tutorials/github_actions.md @@ -0,0 +1,99 @@ +## Create new release with Github Actions + +### Automatic bumping of version + +In order to execute `cz bump` in your CI, and push the new commit and +the new tag, back to your master branch, we have to: +1. Create a personal access token. [Follow the instructions here](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line#creating-a-token). And copy the generated key +2. Create a secret called `PERSONAL_ACCESS_TOKEN`, with the copied key, by going to your +project repository and then `Settings > Secrets > Add new secret`. +3. In your repostiroy create a new file `.github/workflows/bumpversion.yml` +with the following content. + +```yaml +name: Bump version + +on: + push: + branches: + - master # another branch could be specified here + +jobs: + build: + if: "!contains(github.event.head_commit.message, 'bump')" + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['3.x'] + steps: + - uses: actions/checkout@master + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python --version + python --version + python -m pip install -U commitizen + - name: Create bump + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git config --local push.followTags true + cz bump --yes + git tag + - name: Push changes + uses: Woile/github-push-action@master + with: + github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + tags: "true" +``` + +Push to master and that's it. + +### Publishing a python package + +Once the new tag is created, triggering an automatic publish command would be desired. + +In order to do so, first 2 secrets need to be added with the information +of our pypi account. + +Go to `Settings > Secrets > Add new secret` and add the secrets: `PYPI_USERNAME` and `PYPI_PASSWORD`. + +Create a file in `.github/workflows/pythonpublish.yaml` with the following content: + +```yaml +name: Upload Python Package + +on: + push: + tags: + - '*' # Will trigger for every tag, alternative: 'v*' + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Set up Python + uses: actions/setup-python@v1 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --pre -U poetry + poetry --version + poetry install + - name: Build and publish + env: + PYPI_USERNAME: ${{ secrets.PYPI_USERNAME }} + PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + run: | + ./scripts/publish +``` + +Notice that we are calling a bash script in `./scripts/publish`, you should +configure it with your tools (twine, poetry, etc). Check [commitizen example](https://github.com/Woile/commitizen/blob/master/scripts/deploy) + +Push the changes and that's it. \ No newline at end of file From 9f4010162a8774350fcac2035d94d657224aeb5c Mon Sep 17 00:00:00 2001 From: santiago fraire Date: Fri, 22 Nov 2019 19:44:38 +0100 Subject: [PATCH 0027/2044] docs: added github actions to nav --- mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/mkdocs.yml b/mkdocs.yml index 13921fe0c5..0d08e13968 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -15,6 +15,7 @@ nav: - Customization: 'customization.md' - Tutorials: - GitLab CI: 'tutorials/gitlab_ci.md' + - Github Actions: 'tutorials/github_actions.md' markdown_extensions: - markdown.extensions.codehilite: From 90d3568844211119553026d08bdcd4020181e7b4 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 22 Nov 2019 18:46:00 +0000 Subject: [PATCH 0028/2044] =?UTF-8?q?bump:=20version=201.8.0=20=E2=86=92?= =?UTF-8?q?=201.9.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 29654eec0a..0a0a43a57e 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.8.0" +__version__ = "1.9.0" diff --git a/pyproject.toml b/pyproject.toml index bad79fe89f..57ab3a15ed 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.8.0" +version = "1.9.0" tag_format = "v$version" files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.8.0" +version = "1.9.0" description = "Python commitizen client tool" authors = ["Santiago Fraire "] license = "MIT" From 033c8d1d80a575c51ad4e92b21ec6b7ba0f52357 Mon Sep 17 00:00:00 2001 From: santiago fraire Date: Fri, 22 Nov 2019 19:56:08 +0100 Subject: [PATCH 0029/2044] ci: publish with github secret --- .github/workflows/pythonpublish.yaml | 1 + scripts/publish | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pythonpublish.yaml b/.github/workflows/pythonpublish.yaml index bf61909073..55583d1dc2 100644 --- a/.github/workflows/pythonpublish.yaml +++ b/.github/workflows/pythonpublish.yaml @@ -23,5 +23,6 @@ jobs: env: PYPI_USERNAME: ${{ secrets.PYPI_USERNAME }} PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | ./scripts/publish diff --git a/scripts/publish b/scripts/publish index ec97859484..80ed6a7a4f 100755 --- a/scripts/publish +++ b/scripts/publish @@ -1,12 +1,12 @@ # Publish to pypi poetry publish --build -u $PYPI_USERNAME -p $PYPI_PASSWORD -[ -z "${INPUT_GITHUB_TOKEN}" ] && { +[ -z "${GITHUB_TOKEN}" ] && { echo 'Missing input "github_token: ${{ secrets.GITHUB_TOKEN }}".'; exit 1; }; -remote_repo="https://${GITHUB_ACTOR}:${INPUT_GITHUB_TOKEN}@github.com/commitizen.git" +remote_repo="https://${GITHUB_ACTOR}:${GITHUB_TOKEN}@github.com/commitizen.git" # Publish docs mkdocs gh-deploy --remote-name "${remote_repo}" From 65f837dab506e3aee825a6c12da8156e2f5509fb Mon Sep 17 00:00:00 2001 From: santiago fraire Date: Fri, 22 Nov 2019 19:56:23 +0100 Subject: [PATCH 0030/2044] docs: updated changelog --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3f2cbdaec..44a7f8111c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # CHANGELOG -## Unreleased +## v1.9.0 ### Feature @@ -20,6 +20,10 @@ - windows error when removing folders (#67) - typos in docs +### Docs +- tutorial for gitlab ci +- tutorial for github actions + ## v1.8.0 ### Feature From 149a5a9b1ac7f60302608a5e2959b46199b66c0f Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Sat, 23 Nov 2019 05:18:16 -0500 Subject: [PATCH 0031/2044] fix(cz/exceptions): exception AnswerRequiredException not caught (#89) * fix(cz/exceptions): Fix AnswerRequiredException not caught inherit CzException * style(all): run ./script/lint --- commitizen/cli.py | 1 - commitizen/commands/__init__.py | 5 ++--- commitizen/commands/check.py | 8 +++++--- commitizen/cz/__init__.py | 2 +- commitizen/cz/exceptions.py | 2 +- tests/test_bump_command.py | 2 +- tests/test_commands.py | 15 +++++---------- tests/test_cz_customize.py | 2 +- 8 files changed, 16 insertions(+), 21 deletions(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index be6103226a..4b667e1715 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -7,7 +7,6 @@ from commitizen import commands, config, out - logger = logging.getLogger(__name__) data = { "prog": "cz", diff --git a/commitizen/commands/__init__.py b/commitizen/commands/__init__.py index ea17a8a5f3..051429f52f 100644 --- a/commitizen/commands/__init__.py +++ b/commitizen/commands/__init__.py @@ -1,11 +1,10 @@ from .bump import Bump -from .commit import Commit from .check import Check +from .commit import Commit from .example import Example from .info import Info from .list_cz import ListCz from .schema import Schema from .version import Version -__all__ = ("Bump", "Check", "Commit", "Example", "Info", "ListCz", "Schema", - "Version") +__all__ = ("Bump", "Check", "Commit", "Example", "Info", "ListCz", "Schema", "Version") diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py index 67a449a03d..3ebb8c5f9e 100644 --- a/commitizen/commands/check.py +++ b/commitizen/commands/check.py @@ -3,8 +3,10 @@ from commitizen import out -PATTERN = (r'(build|ci|docs|feat|fix|perf|refactor|style|test|chore|revert)' - r'(\([\w\-]+\))?:\s.*') +PATTERN = ( + r"(build|ci|docs|feat|fix|perf|refactor|style|test|chore|revert)" + r"(\([\w\-]+\))?:\s.*" +) NO_COMMIT_MSG = 3 INVALID_COMMIT_MSG = 5 @@ -46,7 +48,7 @@ def __call__(self): def _get_commit_msg(self): temp_filename: str = self.arguments.get("commit_msg_file") - return open(temp_filename, 'r').read() + return open(temp_filename, "r").read() def _is_conventional(self, pattern, commit_msg): return re.match(PATTERN, commit_msg) diff --git a/commitizen/cz/__init__.py b/commitizen/cz/__init__.py index 5951b722d1..3c379f3c6b 100644 --- a/commitizen/cz/__init__.py +++ b/commitizen/cz/__init__.py @@ -2,8 +2,8 @@ import pkgutil from commitizen.cz.conventional_commits import ConventionalCommitsCz -from commitizen.cz.jira import JiraSmartCz from commitizen.cz.customize import CustomizeCommitsCz +from commitizen.cz.jira import JiraSmartCz registry = { "cz_conventional_commits": ConventionalCommitsCz, diff --git a/commitizen/cz/exceptions.py b/commitizen/cz/exceptions.py index 89b19788b7..2597b68813 100644 --- a/commitizen/cz/exceptions.py +++ b/commitizen/cz/exceptions.py @@ -2,5 +2,5 @@ class CzException(Exception): ... -class AnswerRequiredError(Exception): +class AnswerRequiredError(CzException): ... diff --git a/tests/test_bump_command.py b/tests/test_bump_command.py index f39668145c..209a5efe53 100644 --- a/tests/test_bump_command.py +++ b/tests/test_bump_command.py @@ -1,7 +1,7 @@ +import errno import os import shutil import stat -import errno import sys import uuid from pathlib import Path diff --git a/tests/test_commands.py b/tests/test_commands.py index 210e392352..6aaae55eef 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -179,12 +179,11 @@ def test_check_no_conventional_commit(mocker): with get_temp_dir() as dir: tempfile = os.path.join(dir, "temp_commit_file") - with open(tempfile, 'w') as f: + with open(tempfile, "w") as f: f.write("no conventional commit") check_cmd = commands.Check( - config=config, - arguments={"commit_msg_file": tempfile} + config=config, arguments={"commit_msg_file": tempfile} ) check_cmd() error_mock.assert_called_once() @@ -195,12 +194,11 @@ def test_check_conventional_commit(mocker): with get_temp_dir() as dir: tempfile = os.path.join(dir, "temp_commit_file") - with open(tempfile, 'w') as f: + with open(tempfile, "w") as f: f.write("feat(lang): added polish language") check_cmd = commands.Check( - config=config, - arguments={"commit_msg_file": tempfile} + config=config, arguments={"commit_msg_file": tempfile} ) check_cmd() @@ -209,7 +207,4 @@ def test_check_conventional_commit(mocker): def test_check_command_when_commit_file_not_found(): with pytest.raises(FileNotFoundError): - commands.Check( - config=config, - arguments={"commit_msg_file": ""} - )() + commands.Check(config=config, arguments={"commit_msg_file": ""})() diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py index 21fb1272e5..56d58811e5 100644 --- a/tests/test_cz_customize.py +++ b/tests/test_cz_customize.py @@ -1,8 +1,8 @@ import pytest from tomlkit import parse -from commitizen.cz.customize import CustomizeCommitsCz from commitizen.config import Config +from commitizen.cz.customize import CustomizeCommitsCz @pytest.fixture(scope="module") From b9201b1fcdb8e6ec03a421cf9c7cc3435e189a84 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sat, 23 Nov 2019 10:18:51 +0000 Subject: [PATCH 0032/2044] =?UTF-8?q?bump:=20version=201.9.0=20=E2=86=92?= =?UTF-8?q?=201.9.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 0a0a43a57e..38cf6dbeb5 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.9.0" +__version__ = "1.9.1" diff --git a/pyproject.toml b/pyproject.toml index 57ab3a15ed..3182bc3350 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.9.0" +version = "1.9.1" tag_format = "v$version" files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.9.0" +version = "1.9.1" description = "Python commitizen client tool" authors = ["Santiago Fraire "] license = "MIT" From b13bbd5cd9b6a472d9bbec19481964f173320ce6 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Sat, 23 Nov 2019 05:20:44 -0500 Subject: [PATCH 0033/2044] fix(commands/check.py): --commit-msg-file is now a required argument * fix(commands/check.py): make --commit-msg-file a required argument for check command Currently, if --commit-msg-file is not provided, it throws exception * style(all): run ./script/lint --- commitizen/cli.py | 1 + 1 file changed, 1 insertion(+) diff --git a/commitizen/cli.py b/commitizen/cli.py index 4b667e1715..7a68aae766 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -117,6 +117,7 @@ "arguments": [ { "name": "--commit-msg-file", + "required": True, "help": ( "ask for the name of the temporal file that contains " "the commit message. " From dab7cc71fabe3b2721a43e71a87a6774f5cdaa55 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sat, 23 Nov 2019 10:21:16 +0000 Subject: [PATCH 0034/2044] =?UTF-8?q?bump:=20version=201.9.1=20=E2=86=92?= =?UTF-8?q?=201.9.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 38cf6dbeb5..2cbc28c30c 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.9.1" +__version__ = "1.9.2" diff --git a/pyproject.toml b/pyproject.toml index 3182bc3350..56019fdad2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.9.1" +version = "1.9.2" tag_format = "v$version" files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.9.1" +version = "1.9.2" description = "Python commitizen client tool" authors = ["Santiago Fraire "] license = "MIT" From ce9fae41ceeec8d81432e08f57dc023ee417039c Mon Sep 17 00:00:00 2001 From: santiago fraire Date: Sat, 23 Nov 2019 11:23:37 +0100 Subject: [PATCH 0035/2044] ci(pythonpublish): missing mkdocs in deps --- .github/workflows/pythonpublish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pythonpublish.yaml b/.github/workflows/pythonpublish.yaml index 55583d1dc2..b80f08a5df 100644 --- a/.github/workflows/pythonpublish.yaml +++ b/.github/workflows/pythonpublish.yaml @@ -16,7 +16,7 @@ jobs: python-version: '3.x' - name: Install dependencies run: | - python -m pip install --pre -U poetry + python -m pip install --pre -U poetry mkdocs poetry --version poetry install - name: Build and publish From a67171c0ef5771dfb2d41bf4ba96324c9ea1c53b Mon Sep 17 00:00:00 2001 From: santiago fraire Date: Sat, 23 Nov 2019 11:35:04 +0100 Subject: [PATCH 0036/2044] docs(tutorials): updated broken in github actions --- docs/tutorials/github_actions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/github_actions.md b/docs/tutorials/github_actions.md index 04bc976664..5ec4864ce5 100644 --- a/docs/tutorials/github_actions.md +++ b/docs/tutorials/github_actions.md @@ -94,6 +94,6 @@ jobs: ``` Notice that we are calling a bash script in `./scripts/publish`, you should -configure it with your tools (twine, poetry, etc). Check [commitizen example](https://github.com/Woile/commitizen/blob/master/scripts/deploy) +configure it with your tools (twine, poetry, etc). Check [commitizen example](https://github.com/Woile/commitizen/blob/master/scripts/publish) Push the changes and that's it. \ No newline at end of file From 7b634e2c21c9bbcf427a5314930e0465b02b6270 Mon Sep 17 00:00:00 2001 From: santiago fraire Date: Sat, 23 Nov 2019 11:35:26 +0100 Subject: [PATCH 0037/2044] docs(index): updated link to github actions --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index fbd06922b1..cbd8d36caf 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,5 +1,5 @@ -[![Travis](https://img.shields.io/travis/Woile/commitizen.svg?style=flat-square)](https://travis-ci.org/Woile/commitizen) +[![Github Actions](https://github.com/Woile/commitizen/workflows/Python%20package/badge.svg?style=flat-square)](https://github.com/Woile/commitizen/actions) [![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg?style=flat-square)](https://conventionalcommits.org) [![PyPI Package latest From 7ec8c29224d128decb6fcd19715b044c8bbe978c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= Date: Wed, 27 Nov 2019 18:36:15 +0100 Subject: [PATCH 0038/2044] feat(bump): new argument --files-only --- CHANGELOG.md | 18 ++++++++++++++++++ commitizen/cli.py | 5 +++++ commitizen/commands/bump.py | 26 +++++++++++++++++--------- docs/bump.md | 10 ++++++++-- 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44a7f8111c..87b2226761 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # CHANGELOG +## v1.10.0 + +### Feature + +- new argument `--files-only` in bump + +## v1.9.2 + +### Fix + +- `--commit-msg-file` is now a required argument + +## v1.9.1 + +### Fix + +- exception `AnswerRequiredException` not caught + ## v1.9.0 ### Feature diff --git a/commitizen/cli.py b/commitizen/cli.py index 7a68aae766..903775b399 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -73,6 +73,11 @@ "action": "store_true", "help": "show output to stdout, no commit, no modified files", }, + { + "name": "--files-only", + "action": "store_true", + "help": "bump version in the files from the config", + }, { "name": "--yes", "action": "store_true", diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index d017f8a7a6..27d1dd9ee2 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -52,6 +52,17 @@ def is_initial_tag(self, current_tag_version: str, is_yes: bool = False) -> bool is_initial = questionary.confirm("Is this the first tag created?").ask() return is_initial + def find_increment(self, commits: list) -> Optional[str]: + bump_pattern = self.cz.bump_pattern + bump_map = self.cz.bump_map + if not bump_map or not bump_pattern: + out.error(f"'{self.config['name']}' rule does not support bump") + raise SystemExit(NO_PATTERN_MAP) + increment = bump.find_increment( + commits, regex=bump_pattern, increments_map=bump_map + ) + return increment + def __call__(self): """Steps executed to bump.""" try: @@ -75,6 +86,7 @@ def __call__(self): is_yes: bool = self.arguments["yes"] prerelease: str = self.arguments["prerelease"] increment: Optional[str] = self.arguments["increment"] + is_files_only: Optional[bool] = self.arguments["files_only"] is_initial = self.is_initial_tag(current_tag_version, is_yes) commits = git.get_commits(current_tag_version, from_beginning=is_initial) @@ -87,14 +99,7 @@ def __call__(self): raise SystemExit(NO_COMMITS_FOUND) if increment is None: - bump_pattern = self.cz.bump_pattern - bump_map = self.cz.bump_map - if not bump_map or not bump_pattern: - out.error(f"'{self.config['name']}' rule does not support bump") - raise SystemExit(NO_PATTERN_MAP) - increment = bump.find_increment( - commits, regex=bump_pattern, increments_map=bump_map - ) + increment = self.find_increment(commits) # Increment is removed when current and next version # are expected to be prereleases. @@ -118,8 +123,11 @@ def __call__(self): if dry_run: raise SystemExit() - config.set_key("version", new_version.public) bump.update_version_in_files(current_version, new_version.public, files) + if is_files_only: + raise SystemExit() + + config.set_key("version", new_version.public) c = git.commit(message, args="-a") if c.err: out.error('git.commit errror: "{}"'.format(c.err.strip())) diff --git a/docs/bump.md b/docs/bump.md index 6a0a4a542a..fe90322e51 100644 --- a/docs/bump.md +++ b/docs/bump.md @@ -54,16 +54,22 @@ Some examples: ```bash $ cz bump --help -usage: cz bump [-h] [--dry-run] [--tag-format TAG_FORMAT] +usage: cz bump [-h] [--dry-run] [--files-only] [--yes] + [--tag-format TAG_FORMAT] [--bump-message BUMP_MESSAGE] [--prerelease {alpha,beta,rc}] [--increment {MAJOR,MINOR,PATCH}] optional arguments: -h, --help show this help message and exit --dry-run show output to stdout, no commit, no modified files + --files-only bump version in the files from the config + --yes accept automatically questions done --tag-format TAG_FORMAT format used to tag the commmit and read it, use it in - existing projects, wrap around simple quotes. + existing projects, wrap around simple quotes + --bump-message BUMP_MESSAGE + template used to create the release commmit, useful + when working with CI --prerelease {alpha,beta,rc}, -pr {alpha,beta,rc} choose type of prerelease --increment {MAJOR,MINOR,PATCH} From d87cd1ab21d33e7701b4660ef47effbbb432defb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= Date: Wed, 27 Nov 2019 18:47:08 +0100 Subject: [PATCH 0039/2044] docs(bump): added information about .cz deprecation --- docs/bump.md | 60 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/docs/bump.md b/docs/bump.md index fe90322e51..73a02cfb42 100644 --- a/docs/bump.md +++ b/docs/bump.md @@ -92,15 +92,19 @@ cz bump --tag_format="v$version" cz bump --tag_format="v$minor.$major.$path$prerelease" ``` -In your `pyproject.toml` +In your `pyproject.toml` or `.cz.toml` - [tool.commitizen] - tag_format = "v$minor.$major.$path$prerelease" +```toml +[tool.commitizen] +tag_format = "v$minor.$major.$path$prerelease" +``` -Or in your `.cz` +Or in your `.cz` (TO BE DEPRECATED) - [commitizen] - tag_format = v$minor.$major.$path$prerelease +``` +[commitizen] +tag_format = v$minor.$major.$path$prerelease +``` The variables must be preceded by a `$` sign. @@ -126,21 +130,25 @@ regarding if the file is present or not in `files`. Some examples -`pyproject.toml` +`pyproject.toml` or `.cz.toml` - [tool.commitizen] - files = [ - "src/__version__.py", - "setup.py:version" - ] +```toml +[tool.commitizen] +files = [ + "src/__version__.py", + "setup.py:version" +] +``` -`.cz` +`.cz` (TO BE DEPRECATED) - [commitizen] - files = [ - "src/__version__.py", - "setup.py:version" - ] +``` +[commitizen] +files = [ + "src/__version__.py", + "setup.py:version" + ] +``` In the example above, we can see the reference `"setup.py:version"`. This means that it will find a file `setup.py` and will only make a change @@ -161,15 +169,19 @@ defaults to: `bump: version $current_version → $new_version` Some examples -`pyproject.toml` +`pyproject.toml` or `.cz.toml` - [tool.commitizen] - bump_message = "release $current_version → $new_version [skip-ci]" +```toml +[tool.commitizen] +bump_message = "release $current_version → $new_version [skip-ci]" +``` -`.cz` +`.cz` (TO BE DEPRECATED) - [commitizen] - bump_message = release $current_version → $new_version [skip-ci] +``` +[commitizen] +bump_message = release $current_version → $new_version [skip-ci] +``` ## Custom bump From 116abe9d73f04eea72a30caee79d6dee9560b1a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariem=20P=C3=A9rez=20Herrera?= Date: Thu, 28 Nov 2019 05:04:08 -0500 Subject: [PATCH 0040/2044] feat: support for different commitizens in `cz check` * Add support for different commitizens in `cz check` * Fix Jira issue format matching according to https://confluence.atlassian.com/fisheye/using-smart-commits-960155400.html#UsingSmartCommits-GetSmartCommitsworking * Add more tests for cz check --- commitizen/cli.py | 8 +- commitizen/commands/check.py | 23 +++--- commitizen/cz/base.py | 4 + .../conventional_commits.py | 7 ++ commitizen/cz/jira/jira.py | 3 + tests/test_check_command.py | 78 +++++++++++++++++++ 6 files changed, 109 insertions(+), 14 deletions(-) create mode 100644 tests/test_check_command.py diff --git a/commitizen/cli.py b/commitizen/cli.py index 903775b399..da170eefdd 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -18,7 +18,11 @@ "formatter_class": argparse.RawDescriptionHelpFormatter, "arguments": [ {"name": "--debug", "action": "store_true", "help": "use debug mode"}, - {"name": ["-n", "--name"], "help": "use the given commitizen"}, + { + "name": ["-n", "--name"], + "default": "cz_conventional_commits", + "help": "use the given commitizen (default: cz_conventional_commits)", + }, { "name": ["--version"], "action": "store_true", @@ -117,7 +121,7 @@ }, { "name": ["check"], - "help": "enforce the project to always use conventional commits", + "help": "validates that a commit message matches the commitizen schema", "func": commands.Check, "arguments": [ { diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py index 3ebb8c5f9e..35a45530dd 100644 --- a/commitizen/commands/check.py +++ b/commitizen/commands/check.py @@ -1,18 +1,15 @@ import os import re -from commitizen import out +from commitizen import factory, out + -PATTERN = ( - r"(build|ci|docs|feat|fix|perf|refactor|style|test|chore|revert)" - r"(\([\w\-]+\))?:\s.*" -) NO_COMMIT_MSG = 3 INVALID_COMMIT_MSG = 5 class Check: - """Check if the current commit msg is a conventional commit.""" + """Check if the current commit msg matches the commitizen format.""" def __init__(self, config: dict, arguments: dict, cwd=os.getcwd()): """Init method. @@ -27,6 +24,7 @@ def __init__(self, config: dict, arguments: dict, cwd=os.getcwd()): """ self.config: dict = config + self.cz = factory.commiter_factory(self.config) self.arguments: dict = arguments def __call__(self): @@ -39,16 +37,17 @@ def __call__(self): """ commit_msg_content = self._get_commit_msg() - if self._is_conventional(PATTERN, commit_msg_content) is not None: - out.success("Conventional commit validation: successful!") + pattern = self.cz.schema_pattern() + if self._has_proper_format(pattern, commit_msg_content) is not None: + out.success("Commit validation: successful!") else: - out.error("conventional commit validation: failed!") - out.error("please enter a commit message in the conventional format.") + out.error("commit validation: failed!") + out.error("please enter a commit message in the commitizen format.") raise SystemExit(INVALID_COMMIT_MSG) def _get_commit_msg(self): temp_filename: str = self.arguments.get("commit_msg_file") return open(temp_filename, "r").read() - def _is_conventional(self, pattern, commit_msg): - return re.match(PATTERN, commit_msg) + def _has_proper_format(self, pattern, commit_msg): + return re.match(pattern, commit_msg) diff --git a/commitizen/cz/base.py b/commitizen/cz/base.py index 656100ec64..d756be905b 100644 --- a/commitizen/cz/base.py +++ b/commitizen/cz/base.py @@ -47,6 +47,10 @@ def schema(self) -> str: """Schema definition of the commit message.""" raise NotImplementedError("Not Implemented yet") + def schema_pattern(self) -> str: + """Regex matching the schema used for message validation""" + raise NotImplementedError("Not Implemented yet") + def info(self) -> str: """Information about the standardized commit message.""" raise NotImplementedError("Not Implemented yet") diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index bd0ab35885..14e76393d9 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -169,6 +169,13 @@ def schema(self) -> str: "