From 86906146c46cee6b0f08c86a6449711a0c18cc88 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Sun, 8 Mar 2020 17:51:22 +0800 Subject: [PATCH 001/427] refactor(git): remove unnecessary dot between git range --- commitizen/git.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commitizen/git.py b/commitizen/git.py index 0853d76005..1b93a62c95 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -64,7 +64,7 @@ def get_commits( git_log_cmd = f"git log --pretty={log_format}{delimiter}" if start: - c = cmd.run(f"{git_log_cmd} {start}...{end}") + c = cmd.run(f"{git_log_cmd} {start}..{end}") else: c = cmd.run(f"{git_log_cmd} {end}") From 5455936bfd340a6e35c02b33148329fa18c1e2cb Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Sun, 8 Mar 2020 17:53:24 +0800 Subject: [PATCH 002/427] refactor(cz/connventional_commit): use \S to check scope --- commitizen/cz/conventional_commits/conventional_commits.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index c67b2a5a0d..a9bfcf2039 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -172,7 +172,7 @@ def schema(self) -> str: def schema_pattern(self) -> str: PATTERN = ( r"(build|ci|docs|feat|fix|perf|refactor|style|test|chore|revert|bump)" - r"(\([\w\-]+\))?:\s.*" + r"(\(\S+\))?:\s.*" ) return PATTERN From 724aa1c9d35c3f4c38ba308eb167939f9544570b Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Sun, 8 Mar 2020 18:36:14 +0800 Subject: [PATCH 003/427] feat(commands/check): add --rev-range argument for checking commits within some range --- commitizen/cli.py | 9 ++- commitizen/commands/check.py | 57 +++++++++++++------ tests/commands/test_check_command.py | 85 +++++++++++++++++++++++++++- 3 files changed, 129 insertions(+), 22 deletions(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index f7e9f28687..aab677f870 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -151,13 +151,18 @@ "arguments": [ { "name": "--commit-msg-file", - "required": True, "help": ( "ask for the name of the temporal file that contains " "the commit message. " "Using it in a git hook script: MSG_FILE=$1" ), - } + "exclusive_group": "group1", + }, + { + "name": "--rev-range", + "help": ("a reange of git rev to check. e.g, master..HEAD"), + "exclusive_group": "group1", + }, ], }, { diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py index de5f5e39f9..8f3d9dad44 100644 --- a/commitizen/commands/check.py +++ b/commitizen/commands/check.py @@ -1,7 +1,8 @@ import os import re +from typing import Dict -from commitizen import factory, out +from commitizen import factory, git, out from commitizen.config import BaseConfig from commitizen.error_codes import INVALID_COMMIT_MSG @@ -9,7 +10,7 @@ class Check: """Check if the current commit msg matches the commitizen format.""" - def __init__(self, config: BaseConfig, arguments: dict, cwd=os.getcwd()): + def __init__(self, config: BaseConfig, arguments: Dict[str, str], cwd=os.getcwd()): """Init method. Parameters @@ -21,12 +22,21 @@ def __init__(self, config: BaseConfig, arguments: dict, cwd=os.getcwd()): the flags provided by the user """ + self.commit_msg_file: str = arguments.get("commit_msg_file") + self.rev_range: str = arguments.get("rev_range") + + self._valid_command_argument() + self.config: BaseConfig = config self.cz = factory.commiter_factory(self.config) - self.arguments: dict = arguments + + def _valid_command_argument(self): + if bool(self.commit_msg_file) is bool(self.rev_range): + out.error("One and only one argument is required for check command!") + raise SystemExit() def __call__(self): - """Validate if a commit message follows the conventional pattern. + """Validate if commit messages follows the conventional pattern. Raises ------ @@ -34,18 +44,31 @@ def __call__(self): if the commit provided not follows the conventional pattern """ - commit_msg_content = self._get_commit_msg() + commit_msgs = self._get_commit_messages() 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("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 _has_proper_format(self, pattern, commit_msg): + for commit_msg in commit_msgs: + if not Check.validate_commit_message(commit_msg, pattern): + out.error( + "commit validation: failed!\n" + "please enter a commit message in the commitizen format.\n" + f"commit: {commit_msg}\n" + f"pattern: {pattern}" + ) + raise SystemExit(INVALID_COMMIT_MSG) + out.success("Commit validation: successful!") + + def _get_commit_messages(self): + # Get commit message from file (--commit-msg-file) + if self.commit_msg_file: + with open(self.commit_msg_file, "r") as commit_file: + commit_msg = commit_file.read() + return [commit_msg] + + # Get commit messages from git log (--rev-range) + return [commit.message for commit in git.get_commits(end=self.rev_range)] + + @staticmethod + def validate_commit_message(commit_msg: str, pattern: str) -> bool: + if commit_msg.startswith("Merge") or commit_msg.startswith("Revert"): + return True return re.match(pattern, commit_msg) diff --git a/tests/commands/test_check_command.py b/tests/commands/test_check_command.py index a53e57b495..21dfcc2d60 100644 --- a/tests/commands/test_check_command.py +++ b/tests/commands/test_check_command.py @@ -1,9 +1,49 @@ import sys +from typing import List import pytest -from commitizen import cli -from commitizen import commands +from commitizen import cli, git, commands + + +COMMIT_LOG = [ + "refactor: A code change that neither fixes a bug nor adds a feature", + r"refactor(cz/connventional_commit): use \S to check scope", + "refactor(git): remove unnecessary dot between git range", + "bump: version 1.16.3 → 1.16.4", + ( + "Merge pull request #139 from Lee-W/fix-init-clean-config-file\n" + "Fix init clean config file" + ), + "ci(pyproject.toml): add configuration for coverage", + "fix(commands/init): fix clean up file when initialize commitizen config\n#138", + "refactor(defaults): split config files into long term support and deprecated ones", + "bump: version 1.16.2 → 1.16.3", + ( + "Merge pull request #136 from Lee-W/remove-redundant-readme\n" + "Remove redundant readme" + ), + "fix: replace README.rst with docs/README.md in config files", + ( + "refactor(docs): remove README.rst and use docs/README.md\n" + "By removing README.rst, we no longer need to maintain " + "two document with almost the same content\n" + "Github can read docs/README.md as README for the project." + ), + "docs(check): pin pre-commit to v1.16.2", + "docs(check): fix pre-commit setup", + "bump: version 1.16.1 → 1.16.2", + "Merge pull request #135 from Lee-W/fix-pre-commit-hook\nFix pre commit hook", + "docs(check): enforce cz check only whem committing", + ( + 'Revert "fix(pre-commit): set pre-commit check stage to commit-msg"\n' + "This reverts commit afc70133e4a81344928561fbf3bb20738dfc8a0b." + ), +] + + +def _build_fake_git_commits(commit_msgs: List[str]) -> List[git.GitCommit]: + return [git.GitCommit("test_rev", commit_msg) for commit_msg in commit_msgs] def test_check_jira_fails(mocker, capsys): @@ -115,4 +155,43 @@ def test_check_conventional_commit(commit_msg, config, mocker, tmpdir): def test_check_command_when_commit_file_not_found(config): with pytest.raises(FileNotFoundError): - commands.Check(config=config, arguments={"commit_msg_file": ""})() + commands.Check(config=config, arguments={"commit_msg_file": "no_such_file"})() + + +def test_check_a_range_of_git_commits(config, mocker): + success_mock = mocker.patch("commitizen.out.success") + mocker.patch( + "commitizen.git.get_commits", return_value=_build_fake_git_commits(COMMIT_LOG) + ) + + check_cmd = commands.Check( + config=config, arguments={"rev_range": "HEAD~10..master"} + ) + + check_cmd() + success_mock.assert_called_once() + + +def test_check_a_range_of_git_commits_and_failed(config, mocker): + error_mock = mocker.patch("commitizen.out.error") + mocker.patch( + "commitizen.git.get_commits", + return_value=_build_fake_git_commits(["This commit does not follow rule"]), + ) + check_cmd = commands.Check( + config=config, arguments={"rev_range": "HEAD~10..master"} + ) + + with pytest.raises(SystemExit): + check_cmd() + error_mock.assert_called_once() + + +@pytest.mark.parametrize( + "args", [{"rev_range": "HEAD~10..master", "commit_msg_file": "some_file"}, {}] +) +def test_check_command_with_invalid_argment(args, config, capsys): + with pytest.raises(SystemExit): + commands.Check(config=config, arguments=args) + _, err = capsys.readouterr() + assert "One and only one argument is required for check command!" in err From 6f19b13f67b1613f1cbe70f9ed45cfb59ecbb1b5 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Sun, 8 Mar 2020 18:48:56 +0800 Subject: [PATCH 004/427] ci(scripts/lint): move isort config to pyproject.toml --- pyproject.toml | 7 +++++++ scripts/lint | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a62517c2f6..d09c9d4d3f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,6 +70,13 @@ isort = "^4.3.21" cz = "commitizen.cli:main" git-cz = "commitizen.cli:main" +[tool.isort] +multi_line_output = 3 +include_trailing_comma = true +force_grid_wrap = 0 +combine_as_imports = true +line_length = 88 + [tool.coverage] [tool.coverage.report] show_missing = true diff --git a/scripts/lint b/scripts/lint index d737c8f476..c643dbc14b 100755 --- a/scripts/lint +++ b/scripts/lint @@ -1,11 +1,11 @@ #!/bin/sh -e -export PREFIX="" +export PREFIX="poetry run python -m " if [ -d 'venv' ] ; then export PREFIX="venv/bin/" fi set -x -${PREFIX}isort --multi-line=3 --trailing-comma --force-grid-wrap=0 --combine-as --line-width 88 --recursive --apply commitizen tests +${PREFIX}isort --recursive --apply commitizen tests ${PREFIX}black commitizen tests From 027d4a2abaaa33e9f3fb0aa7488f593cbadb86c7 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Sun, 8 Mar 2020 18:49:13 +0800 Subject: [PATCH 005/427] ci(scripts/test): add isort check to srctips/test --- scripts/test | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/test b/scripts/test index 119cf67098..6a8082162e 100755 --- a/scripts/test +++ b/scripts/test @@ -7,4 +7,5 @@ fi ${PREFIX}pytest --cov-report term-missing --cov-report=xml:coverage.xml --cov=commitizen tests/ ${PREFIX}black commitizen tests --check +${PREFIX}isort --recursive --check-only commitizen tests ${PREFIX}flake8 --max-line-length=88 commitizen/ tests/ From 4de0008e7677825913a691d9bb5d485063dcbacd Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Sun, 8 Mar 2020 18:36:25 +0800 Subject: [PATCH 006/427] style: isort --- commitizen/bump.py | 2 +- commitizen/commands/__init__.py | 3 +-- commitizen/commands/bump.py | 6 +++--- commitizen/commands/commit.py | 6 +++--- commitizen/commands/init.py | 7 +++---- commitizen/commands/list_cz.py | 2 +- commitizen/commands/version.py | 2 +- commitizen/config/__init__.py | 3 ++- commitizen/cz/customize/customize.py | 2 +- commitizen/factory.py | 2 +- commitizen/git.py | 2 +- tests/commands/test_check_command.py | 3 +-- tests/test_conf.py | 1 - tests/test_cz_base.py | 2 +- tests/test_cz_conventional_commits.py | 3 +-- tests/test_cz_jira.py | 2 +- tests/test_cz_utils.py | 2 +- 17 files changed, 23 insertions(+), 27 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index bfda1c4541..112d27e89a 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -6,7 +6,6 @@ from packaging.version import Version -from commitizen.git import GitCommit from commitizen.defaults import ( MAJOR, MINOR, @@ -15,6 +14,7 @@ bump_message, bump_pattern, ) +from commitizen.git import GitCommit def find_increment( diff --git a/commitizen/commands/__init__.py b/commitizen/commands/__init__.py index e315a987c9..b87906d8b4 100644 --- a/commitizen/commands/__init__.py +++ b/commitizen/commands/__init__.py @@ -3,11 +3,10 @@ from .commit import Commit from .example import Example from .info import Info +from .init import Init from .list_cz import ListCz from .schema import Schema from .version import Version -from .init import Init - __all__ = ( "Bump", diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 605fde9878..90ec715744 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -1,4 +1,4 @@ -from typing import Optional, List +from typing import List, Optional import questionary from packaging.version import Version @@ -6,10 +6,10 @@ from commitizen import bump, factory, git, out from commitizen.config import BaseConfig from commitizen.error_codes import ( + COMMIT_FAILED, NO_COMMITS_FOUND, - NO_VERSION_SPECIFIED, NO_PATTERN_MAP, - COMMIT_FAILED, + NO_VERSION_SPECIFIED, TAG_FAILED, ) diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index 0dbbe8fe9d..57444011fd 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -5,14 +5,14 @@ import questionary from commitizen import factory, git, out -from commitizen.cz.exceptions import CzException from commitizen.config import BaseConfig +from commitizen.cz.exceptions import CzException from commitizen.error_codes import ( - NO_ANSWERS, COMMIT_ERROR, + CUSTOM_ERROR, + NO_ANSWERS, NO_COMMIT_BACKUP, NOTHING_TO_COMMIT, - CUSTOM_ERROR, ) diff --git a/commitizen/commands/init.py b/commitizen/commands/init.py index cd10edf7f7..b428d696cd 100644 --- a/commitizen/commands/init.py +++ b/commitizen/commands/init.py @@ -1,12 +1,11 @@ -from packaging.version import Version - import questionary +from packaging.version import Version from commitizen import factory, out +from commitizen.config import BaseConfig, IniConfig, TomlConfig from commitizen.cz import registry -from commitizen.config import BaseConfig, TomlConfig, IniConfig -from commitizen.git import get_latest_tag_name, get_tag_names from commitizen.defaults import long_term_support_config_files +from commitizen.git import get_latest_tag_name, get_tag_names class Init: diff --git a/commitizen/commands/list_cz.py b/commitizen/commands/list_cz.py index 3f418f440b..99701865af 100644 --- a/commitizen/commands/list_cz.py +++ b/commitizen/commands/list_cz.py @@ -1,6 +1,6 @@ from commitizen import out -from commitizen.cz import registry from commitizen.config import BaseConfig +from commitizen.cz import registry class ListCz: diff --git a/commitizen/commands/version.py b/commitizen/commands/version.py index d64d8d82af..344920c72a 100644 --- a/commitizen/commands/version.py +++ b/commitizen/commands/version.py @@ -1,6 +1,6 @@ from commitizen import out -from commitizen.config import BaseConfig from commitizen.__version__ import __version__ +from commitizen.config import BaseConfig class Version: diff --git a/commitizen/config/__init__.py b/commitizen/config/__init__.py index 88949f327d..9b317f1e36 100644 --- a/commitizen/config/__init__.py +++ b/commitizen/config/__init__.py @@ -4,9 +4,10 @@ from commitizen import defaults, git, out from commitizen.error_codes import NOT_A_GIT_PROJECT + from .base_config import BaseConfig -from .toml_config import TomlConfig from .ini_config import IniConfig +from .toml_config import TomlConfig def load_global_conf() -> Optional[IniConfig]: diff --git a/commitizen/cz/customize/customize.py b/commitizen/cz/customize/customize.py index 46ea0602d9..1e10975fe8 100644 --- a/commitizen/cz/customize/customize.py +++ b/commitizen/cz/customize/customize.py @@ -4,8 +4,8 @@ from string import Template from commitizen import defaults -from commitizen.cz.base import BaseCommitizen from commitizen.config import BaseConfig +from commitizen.cz.base import BaseCommitizen __all__ = ["CustomizeCommitsCz"] diff --git a/commitizen/factory.py b/commitizen/factory.py index 62b7ba9cfa..8dab0c408a 100644 --- a/commitizen/factory.py +++ b/commitizen/factory.py @@ -1,6 +1,6 @@ from commitizen import BaseCommitizen, out -from commitizen.cz import registry from commitizen.config import BaseConfig +from commitizen.cz import registry from commitizen.error_codes import NO_COMMITIZEN_FOUND diff --git a/commitizen/git.py b/commitizen/git.py index 1b93a62c95..058ba89a00 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -1,7 +1,7 @@ import os from pathlib import Path from tempfile import NamedTemporaryFile -from typing import Optional, List +from typing import List, Optional from commitizen import cmd diff --git a/tests/commands/test_check_command.py b/tests/commands/test_check_command.py index 21dfcc2d60..e5fe53b518 100644 --- a/tests/commands/test_check_command.py +++ b/tests/commands/test_check_command.py @@ -3,8 +3,7 @@ import pytest -from commitizen import cli, git, commands - +from commitizen import cli, commands, git COMMIT_LOG = [ "refactor: A code change that neither fixes a bug nor adds a feature", diff --git a/tests/test_conf.py b/tests/test_conf.py index 5320051044..277234e5e5 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -5,7 +5,6 @@ from commitizen import config, defaults, git - PYPROJECT = """ [tool.commitizen] name = "cz_jira" diff --git a/tests/test_cz_base.py b/tests/test_cz_base.py index 82925388ef..b3b8fe4fb8 100644 --- a/tests/test_cz_base.py +++ b/tests/test_cz_base.py @@ -1,8 +1,8 @@ import pytest from commitizen import defaults -from commitizen.cz.base import BaseCommitizen from commitizen.config import BaseConfig +from commitizen.cz.base import BaseCommitizen @pytest.fixture() diff --git a/tests/test_cz_conventional_commits.py b/tests/test_cz_conventional_commits.py index dd6cfbff30..41ed9b0b7d 100644 --- a/tests/test_cz_conventional_commits.py +++ b/tests/test_cz_conventional_commits.py @@ -1,14 +1,13 @@ import pytest from commitizen import defaults +from commitizen.config import BaseConfig from commitizen.cz.conventional_commits.conventional_commits import ( ConventionalCommitsCz, parse_scope, parse_subject, ) from commitizen.cz.exceptions import AnswerRequiredError -from commitizen.config import BaseConfig - valid_scopes = ["", "simple", "dash-separated", "camelCase" "UPPERCASE"] diff --git a/tests/test_cz_jira.py b/tests/test_cz_jira.py index 0c05b46a3c..b725a46fa9 100644 --- a/tests/test_cz_jira.py +++ b/tests/test_cz_jira.py @@ -1,8 +1,8 @@ import pytest from commitizen import defaults -from commitizen.cz.jira import JiraSmartCz from commitizen.config import BaseConfig +from commitizen.cz.jira import JiraSmartCz @pytest.fixture() diff --git a/tests/test_cz_utils.py b/tests/test_cz_utils.py index a8a56d762c..94cc7f5b87 100644 --- a/tests/test_cz_utils.py +++ b/tests/test_cz_utils.py @@ -1,6 +1,6 @@ import pytest -from commitizen.cz import utils, exceptions +from commitizen.cz import exceptions, utils def test_required_validator(): From a8d5b748045ce5ffbb9657ad3e4691aced8a8c30 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 11 Mar 2020 04:19:35 +0000 Subject: [PATCH 007/427] build(deps-dev): update mypy requirement from ^0.761 to ^0.770 Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version. - [Release notes](https://github.com/python/mypy/releases) - [Commits](https://github.com/python/mypy/compare/v0.761...v0.770) Signed-off-by: dependabot-preview[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a62517c2f6..b9e8d67e47 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ flake8 = "^3.6" pytest-cov = "^2.6" pytest-mock = "^2.0" codecov = "^2.0" -mypy = "^0.761" +mypy = "^0.770" mkdocs = "^1.0" mkdocs-material = "^4.1" isort = "^4.3.21" From 17c7d3112b7e3d32e586cf6753176d2cb7ebdc3a Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 13 Mar 2020 17:54:19 +0800 Subject: [PATCH 008/427] fix(bump): fix bump find_increment error in the previous design, MAJOR will be overwritten by other --- commitizen/bump.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index bfda1c4541..bd7b972cab 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -34,12 +34,12 @@ def find_increment( continue found_keyword = result.group(0) new_increment = increments_map_default[found_keyword] - if new_increment == "MAJOR": - increment = new_increment - break - elif increment == "MINOR" and new_increment == "PATCH": + if increment == "MAJOR": continue - increment = new_increment + elif increment == "MINOR" and new_increment == "MAJOR": + increment = new_increment + elif increment == "PATCH" or increment is None: + increment = new_increment return increment From 3cbfc1a0b5cc4c8f05f83dbbbfd4512cac4f8f0c Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 13 Mar 2020 18:05:14 +0800 Subject: [PATCH 009/427] test(config): add omit config for coverage --- pyproject.toml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index a62517c2f6..4c14188bc7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,6 +89,13 @@ git-cz = "commitizen.cli:main" 'if 0:', 'if __name__ == .__main__.:' ] + omit = [ + 'env/*', + 'venv/*', + '*/virtualenv/*', + '*/virtualenvs/*', + '*/tests/*' + ] [build-system] requires = ["poetry>=0.12"] From 1f185ab823ee67a523bc7fb17e3714e930f5929c Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 13 Mar 2020 18:05:54 +0800 Subject: [PATCH 010/427] refactor(tests/bump): use parameterize to group similliar tests --- tests/test_bump_find_increment.py | 74 +++++++++++-------------------- 1 file changed, 25 insertions(+), 49 deletions(-) diff --git a/tests/test_bump_find_increment.py b/tests/test_bump_find_increment.py index 405410712a..30e658c623 100644 --- a/tests/test_bump_find_increment.py +++ b/tests/test_bump_find_increment.py @@ -2,6 +2,8 @@ CC: Conventional commits SVE: Semantic version at the end """ +import pytest + from commitizen import bump from commitizen.git import GitCommit @@ -44,58 +46,32 @@ semantic_version_map = {"MAJOR": "MAJOR", "MINOR": "MINOR", "PATCH": "PATCH"} -def test_find_increment_type_patch(): - messages = PATCH_INCREMENTS_CC - commits = [GitCommit(rev="test", title=message) for message in messages] - increment_type = bump.find_increment(commits) - assert increment_type == "PATCH" - - -def test_find_increment_type_minor(): - messages = MINOR_INCREMENTS_CC +@pytest.mark.parametrize( + "messages, expected_type", + ( + (PATCH_INCREMENTS_CC, "PATCH"), + (MINOR_INCREMENTS_CC, "MINOR"), + (MAJOR_INCREMENTS_CC, "MAJOR"), + (NONE_INCREMENT_CC, None), + ), +) +def test_find_increment(messages, expected_type): commits = [GitCommit(rev="test", title=message) for message in messages] increment_type = bump.find_increment(commits) - assert increment_type == "MINOR" - - -def test_find_increment_type_major(): - messages = MAJOR_INCREMENTS_CC - commits = [GitCommit(rev="test", title=message) for message in messages] - increment_type = bump.find_increment(commits) - assert increment_type == "MAJOR" - - -def test_find_increment_type_patch_sve(): - messages = PATCH_INCREMENTS_SVE - commits = [GitCommit(rev="test", title=message) for message in messages] - increment_type = bump.find_increment( - commits, regex=semantic_version_pattern, increments_map=semantic_version_map - ) - assert increment_type == "PATCH" - - -def test_find_increment_type_minor_sve(): - messages = MINOR_INCREMENTS_SVE - commits = [GitCommit(rev="test", title=message) for message in messages] - increment_type = bump.find_increment( - commits, regex=semantic_version_pattern, increments_map=semantic_version_map - ) - assert increment_type == "MINOR" - - -def test_find_increment_type_major_sve(): - messages = MAJOR_INCREMENTS_SVE - commits = [GitCommit(rev="test", title=message) for message in messages] - increment_type = bump.find_increment( - commits, regex=semantic_version_pattern, increments_map=semantic_version_map - ) - assert increment_type == "MAJOR" - - -def test_find_increment_type_none(): - messages = NONE_INCREMENT_CC + assert increment_type == expected_type + + +@pytest.mark.parametrize( + "messages, expected_type", + ( + (PATCH_INCREMENTS_SVE, "PATCH"), + (MINOR_INCREMENTS_SVE, "MINOR"), + (MAJOR_INCREMENTS_SVE, "MAJOR"), + ), +) +def test_find_increment_sve(messages, expected_type): commits = [GitCommit(rev="test", title=message) for message in messages] increment_type = bump.find_increment( commits, regex=semantic_version_pattern, increments_map=semantic_version_map ) - assert increment_type is None + assert increment_type == expected_type From 6d89df3c9f35b05a1daa1fa65746873ed196d904 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 13 Mar 2020 18:11:04 +0800 Subject: [PATCH 011/427] test(bump_find_increment): reorder major commit for confirming that the order of commits does not matter --- tests/test_bump_find_increment.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_bump_find_increment.py b/tests/test_bump_find_increment.py index 30e658c623..5930be078f 100644 --- a/tests/test_bump_find_increment.py +++ b/tests/test_bump_find_increment.py @@ -10,8 +10,8 @@ NONE_INCREMENT_CC = ["docs(README): motivation", "ci: added travis"] PATCH_INCREMENTS_CC = [ - "docs(README): motivation", "fix(setup.py): future is now required for every python version", + "docs(README): motivation", ] MINOR_INCREMENTS_CC = [ @@ -23,8 +23,8 @@ MAJOR_INCREMENTS_CC = [ "feat(cli): added version", "docs(README): motivation", - "fix(setup.py): future is now required for every python version", "BREAKING CHANGE: `extends` key in config file is now used for extending other config files", # noqa + "fix(setup.py): future is now required for every python version", ] PATCH_INCREMENTS_SVE = ["readme motivation PATCH", "fix setup.py PATCH"] From b471efc142edf3420db4849a3407306054b6e911 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 15 Mar 2020 17:47:55 +0000 Subject: [PATCH 012/427] =?UTF-8?q?bump:=20version=201.16.4=20=E2=86=92=20?= =?UTF-8?q?1.17.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 67f76446fd..30244104a5 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.16.4" +__version__ = "1.17.0" diff --git a/pyproject.toml b/pyproject.toml index 484d85ba48..aa4e141bea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.16.4" +version = "1.17.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.16.4" +version = "1.17.0" description = "Python commitizen client tool" authors = ["Santiago Fraire "] license = "MIT" From df85d2496e8fb32cab57cedeea88097a8930bf02 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Wed, 18 Mar 2020 18:52:25 +0800 Subject: [PATCH 013/427] docs: update doc url due to moving from Woile/commitizen to commitizen-tools/commitizen #145 --- docs/README.md | 6 +++--- docs/check.md | 4 ++-- docs/config.md | 8 ++++---- docs/customization.md | 2 +- docs/tutorials/github_actions.md | 2 +- docs/tutorials/gitlab_ci.md | 2 +- docs/tutorials/writing_commits.md | 2 +- mkdocs.yml | 4 ++-- pyproject.toml | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/README.md b/docs/README.md index 561d9487e1..7604a5b028 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,11 +1,11 @@ -[![Github Actions](https://github.com/Woile/commitizen/workflows/Python%20package/badge.svg?style=flat-square)](https://github.com/Woile/commitizen/actions) +[![Github Actions](https://github.com/commitizen-tools/commitizen/workflows/Python%20package/badge.svg?style=flat-square)](https://github.com/commitizen-tools/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 release](https://img.shields.io/pypi/v/commitizen.svg?style=flat-square)](https://pypi.org/project/commitizen/) [![Supported versions](https://img.shields.io/pypi/pyversions/commitizen.svg?style=flat-square)](https://pypi.org/project/commitizen/) -[![Codecov](https://img.shields.io/codecov/c/github/Woile/commitizen.svg?style=flat-square)](https://codecov.io/gh/Woile/commitizen) +[![Codecov](https://img.shields.io/codecov/c/github/commitizen-tools/commitizen.svg?style=flat-square)](https://codecov.io/gh/commitizen-tools/commitizen) ![Using commitizen cli](images/demo.gif) @@ -115,4 +115,4 @@ Feel free to create a PR. [semver]: https://semver.org/ [keepchangelog]: https://keepachangelog.com/ [gitscm]: https://git-scm.com/downloads -[travis]: https://img.shields.io/travis/Woile/commitizen.svg?style=flat-square +[travis]: https://img.shields.io/travis/commitizen-tools/commitizen.svg?style=flat-square diff --git a/docs/check.md b/docs/check.md index e43878700f..ab325aafee 100644 --- a/docs/check.md +++ b/docs/check.md @@ -16,8 +16,8 @@ python -m pip install pre-commit ```yaml --- repos: - - repo: https://github.com/Woile/commitizen - rev: v1.16.2 + - repo: https://github.com/commitizen-tools/commitizen + rev: v1.17.0 hooks: - id: commitizen stages: [commit-msg] diff --git a/docs/config.md b/docs/config.md index 88f4850d45..32fa3391d8 100644 --- a/docs/config.md +++ b/docs/config.md @@ -67,8 +67,8 @@ The extra tab before the square brackets (`]`) at the end is required. | -------- | ---- | ------- | ----------- | | `name` | `str` | `"cz_conventional_commits"` | Name of the commiting rules to use | | `version` | `str` | `None` | Current version. Example: "0.1.2" | -| `version_files` | `list` | `[ ]` | Files were the version will be updated. A pattern to match a line, can also be specified, separated by `:` [See more](https://woile.github.io/commitizen/bump#files) | -| `tag_format` | `str` | `None` | Format for the git tag, useful for old projects, that use a convention like `"v1.2.1"`. [See more](https://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) | +| `version_files` | `list` | `[ ]` | Files were the version will be updated. A pattern to match a line, can also be specified, separated by `:` [See more](https://commitizen-tools.github.io/commitizen/bump#files) | +| `tag_format` | `str` | `None` | Format for the git tag, useful for old projects, that use a convention like `"v1.2.1"`. [See more](https://commitizen-tools.github.io/commitizen/bump#tag_format) | +| `bump_message` | `str` | `None` | Create custom commit message, useful to skip ci. [See more](https://commitizen-tools.github.io/commitizen/bump#bump_message) | | `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/) | +| `customize` | `dict` | `None` | **This is only supported when config through `toml`.** Custom rules for committing and bumping. [See more](https://commitizen-tools.github.io/commitizen/customization/) | diff --git a/docs/customization.md b/docs/customization.md index 09c996d88c..3e0221b396 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -130,7 +130,7 @@ That's it, your commitizen now supports custom rules, and you can run. cz -n cz_strange bump ``` -[convcomms]: https://github.com/Woile/commitizen/blob/master/commitizen/cz/conventional_commits/conventional_commits.py +[convcomms]: https://github.com/commitizen-tools/commitizen/blob/master/commitizen/cz/conventional_commits/conventional_commits.py ### Raise Customize Exception diff --git a/docs/tutorials/github_actions.md b/docs/tutorials/github_actions.md index b151c9e77a..409428d1bc 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/publish) +configure it with your tools (twine, poetry, etc.). Check [commitizen example](https://github.com/commitizen-tools/commitizen/blob/master/scripts/publish) Push the changes and that's it. diff --git a/docs/tutorials/gitlab_ci.md b/docs/tutorials/gitlab_ci.md index e2da81d63d..18756d4668 100644 --- a/docs/tutorials/gitlab_ci.md +++ b/docs/tutorials/gitlab_ci.md @@ -10,7 +10,7 @@ For this example, we have a `python/django` application and `Docker` as a contai 2. A developer creates a merge request (MR) against `master` branch 3. When the `MR` is merged into master, the 2 stages of the CI are executed 4. For simplification, we store the software version in a file called `VERSION`. You can use any file that you want as `commitizen` supports it. -5. The commit message executed automatically by the `CI` must include `[skip-ci]` in the message; otherwise, the process will generate a loop. You can define the message structure in [commitizen](https://woile.github.io/commitizen/bump/) as well. +5. The commit message executed automatically by the `CI` must include `[skip-ci]` in the message; otherwise, the process will generate a loop. You can define the message structure in [commitizen](https://commitizen-tools.github.io/commitizen/bump/) as well. #### Gitlab Configuration: diff --git a/docs/tutorials/writing_commits.md b/docs/tutorials/writing_commits.md index 37b83b36b7..c981df004c 100644 --- a/docs/tutorials/writing_commits.md +++ b/docs/tutorials/writing_commits.md @@ -35,5 +35,5 @@ understand what happened. | `fix(commands): bump error when no user provided` | `fix: stuff` | | `feat: add new commit command` | `feat: commit command introduced` | -[customization]: https://woile.github.io/commitizen/customization/ +[customization]: https://commitizen-tools.github.io/commitizen/customization/ [conventional_commits]: https://www.conventionalcommits.org diff --git a/mkdocs.yml b/mkdocs.yml index dfaa6e16d8..46499871bc 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -4,8 +4,8 @@ site_description: commit rules, semantic version, conventional commits theme: name: 'material' -repo_name: Woile/commitizen -repo_url: https://github.com/Woile/commitizen +repo_name: commitizen-tools/commitizen +repo_url: https://github.com/commitizen-tools/commitizen edit_uri: "" nav: diff --git a/pyproject.toml b/pyproject.toml index aa4e141bea..47b9b6c5b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,7 @@ authors = ["Santiago Fraire "] license = "MIT" keywords = ["commitizen", "conventional", "commits", "git"] readme = "docs/README.md" -homepage = "https://github.com/woile/commitizen" +homepage = "https://github.com/commitizen-tools/commitizen" classifiers = [ "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.6", From 5a5bec10efa565b059913ca793e64a2c2c4a5336 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Wed, 18 Mar 2020 21:50:26 +0800 Subject: [PATCH 014/427] ci(travis): remove travis related settings --- .travis.yml | 16 ---------------- docs/README.md | 1 - 2 files changed, 17 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 8ecc162156..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -language: python -python: - - "3.6" - - "3.7" - - "3.8" -dist: xenial -sudo: true -install: - - pip install -U poetry - - poetry install - -script: - - ./scripts/test - -after_success: - - codecov \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 7604a5b028..1f7166aff0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -115,4 +115,3 @@ Feel free to create a PR. [semver]: https://semver.org/ [keepchangelog]: https://keepachangelog.com/ [gitscm]: https://git-scm.com/downloads -[travis]: https://img.shields.io/travis/commitizen-tools/commitizen.svg?style=flat-square From 44b81a460c1af95b68c9d5bdabff0a5c3071fc50 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 19 Mar 2020 07:56:41 +0800 Subject: [PATCH 015/427] docs(customization): update cookicutter template url commitizen_cz_template is moved from Lee-W to commitizen-tools --- docs/customization.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/customization.md b/docs/customization.md index 3e0221b396..8419e3d575 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -14,10 +14,10 @@ Check an [example](convcomms) on how to configure `BaseCommitizen`. You can also automate the steps above through [cookiecutter](https://cookiecutter.readthedocs.io/en/1.7.0/). ```sh -cookiecutter gh:Lee-W/commitizen_cz_template +cookiecutter gh:commitizen-tools/commitizen_cz_template ``` -See [Lee-W/commitizen_cz_template](https://github.com/Lee-W/commitizen_cz_template) for detail. +See [commitizen_cz_template](https://github.com/commitizen-tools/commitizen_cz_template) for detail. ### Custom commit rules From 61411f7eeda8d7f92f2624c2875828bb8f16598f Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Tue, 24 Mar 2020 12:12:00 +0800 Subject: [PATCH 016/427] refactor(cli): fix typo --- commitizen/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index aab677f870..4ea45d431b 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -160,7 +160,7 @@ }, { "name": "--rev-range", - "help": ("a reange of git rev to check. e.g, master..HEAD"), + "help": "a range of git rev to check. e.g, master..HEAD", "exclusive_group": "group1", }, ], From 49fc9644cf796d5ff97489dfa8036eaf0c89ad11 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Tue, 24 Mar 2020 12:14:22 +0800 Subject: [PATCH 017/427] fix(commands/check): add help text for check command without argument one argument is needed for check command however, argparse doesn't provide functionality to check such case thus, it's not possible to call `cz check -h` again when argument is not provided --- commitizen/commands/check.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py index 8f3d9dad44..830cb6bb85 100644 --- a/commitizen/commands/check.py +++ b/commitizen/commands/check.py @@ -32,7 +32,12 @@ def __init__(self, config: BaseConfig, arguments: Dict[str, str], cwd=os.getcwd( def _valid_command_argument(self): if bool(self.commit_msg_file) is bool(self.rev_range): - out.error("One and only one argument is required for check command!") + out.error( + ( + "One and only one argument is required for check command! " + "See 'cz check -h' for more information" + ) + ) raise SystemExit() def __call__(self): From ba860ac1b3678659de60cbf565e7fb3faf1a6699 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 24 Mar 2020 04:21:15 +0000 Subject: [PATCH 018/427] =?UTF-8?q?bump:=20version=201.17.0=20=E2=86=92=20?= =?UTF-8?q?1.17.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 30244104a5..c7bbe49657 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.17.0" +__version__ = "1.17.1" diff --git a/pyproject.toml b/pyproject.toml index 47b9b6c5b3..b5b4560657 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.17.0" +version = "1.17.1" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.17.0" +version = "1.17.1" description = "Python commitizen client tool" authors = ["Santiago Fraire "] license = "MIT" From 97260795b4a896af028c020f4ccb69d4495ced61 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Tue, 7 Apr 2020 18:17:26 +0800 Subject: [PATCH 019/427] docs(FAQ): add revert and chore types discussion --- docs/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/README.md b/docs/README.md index 1f7166aff0..bf689b4584 100644 --- a/docs/README.md +++ b/docs/README.md @@ -102,6 +102,23 @@ commands: init init commitizen configuration ``` +## FAQ + +### Why are `revert` and `chore` valid types in the check pattern of cz conventional_commits but not types we can select? + +`revert` and `chore` are added to the "pattern" in `cz check` in order to prevent backward errors, but officially they are not part of conventional commits, we are using the latest [types from Angular](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#type) (they used to but were removed). Using `chore` or `revert` would be part of a different custom rule. + +However, you can always create a customized `cz` with those extra types (See [Customization](https://commitizen-tools.github.io/commitizen/customization/). + +See more discussion in issue [#142](https://github.com/commitizen-tools/commitizen/issues/142) and [#36](https://github.com/commitizen-tools/commitizen/issues/36) + +### How to handle revert commits? + +```sh +git revert --no-commit +git commit -m "revert: foo bar" +``` + ## Contributing Feel free to create a PR. From 227c0514398540f6a739e143f6aa9b60a664b35c Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Tue, 7 Apr 2020 18:45:24 +0800 Subject: [PATCH 020/427] docs: fix typo and wording --- docs/README.md | 9 ++++----- docs/bump.md | 2 +- docs/check.md | 2 +- docs/config.md | 2 +- docs/customization.md | 8 ++++---- docs/init.md | 2 +- docs/tutorials/gitlab_ci.md | 2 +- docs/tutorials/writing_commits.md | 2 +- 8 files changed, 14 insertions(+), 15 deletions(-) diff --git a/docs/README.md b/docs/README.md index bf689b4584..c3f94ccf64 100644 --- a/docs/README.md +++ b/docs/README.md @@ -27,7 +27,7 @@ the version or a changelog. - Command-line utility to create commits with your rules. Defaults: [Conventional commits][conventional_commits] - Display information about your commit rules (commands: schema, example, info) -- Bump version automatically using [semantic verisoning][semver] based on the commits. [Read More](./bump.md) +- Bump version automatically using [semantic versioning][semver] based on the commits. [Read More](./bump.md) - Generate a changelog using [Keep a changelog][keepchangelog] (Planned feature) ## Requirements @@ -58,7 +58,7 @@ poetry add commitizen --dev ## Usage -### Commiting +### Committing Run in your terminal @@ -106,9 +106,8 @@ commands: ### Why are `revert` and `chore` valid types in the check pattern of cz conventional_commits but not types we can select? -`revert` and `chore` are added to the "pattern" in `cz check` in order to prevent backward errors, but officially they are not part of conventional commits, we are using the latest [types from Angular](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#type) (they used to but were removed). Using `chore` or `revert` would be part of a different custom rule. - -However, you can always create a customized `cz` with those extra types (See [Customization](https://commitizen-tools.github.io/commitizen/customization/). +`revert` and `chore` are added to the "pattern" in `cz check` in order to prevent backward errors, but officially they are not part of conventional commits, we are using the latest [types from Angular](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#type) (they used to but were removed). +However, you can create a customized `cz` with those extra types. (See [Customization](https://commitizen-tools.github.io/commitizen/customization/) See more discussion in issue [#142](https://github.com/commitizen-tools/commitizen/issues/142) and [#36](https://github.com/commitizen-tools/commitizen/issues/36) diff --git a/docs/bump.md b/docs/bump.md index bac589a3b2..393baefd15 100644 --- a/docs/bump.md +++ b/docs/bump.md @@ -108,7 +108,7 @@ tag_format = v$minor.$major.$patch$prerelease The variables must be preceded by a `$` sign. -Suppported variables: +Supported variables: | Variable | Description | | ------------- | ------------------------------------------ | diff --git a/docs/check.md b/docs/check.md index ab325aafee..af1c2a56dd 100644 --- a/docs/check.md +++ b/docs/check.md @@ -59,4 +59,4 @@ The `--commit-msg-file` flag is required, not optional. Each time you create a commit, automatically, this hook will analyze it. If the commit message is invalid, it'll be rejected. -The commit should follow the given commiting rules; otherwise, it won't be accepted. +The commit should follow the given committing rules; otherwise, it won't be accepted. diff --git a/docs/config.md b/docs/config.md index 32fa3391d8..d34c228ff9 100644 --- a/docs/config.md +++ b/docs/config.md @@ -65,7 +65,7 @@ The extra tab before the square brackets (`]`) at the end is required. | Variable | Type | Default | Description | | -------- | ---- | ------- | ----------- | -| `name` | `str` | `"cz_conventional_commits"` | Name of the commiting rules to use | +| `name` | `str` | `"cz_conventional_commits"` | Name of the committing rules to use | | `version` | `str` | `None` | Current version. Example: "0.1.2" | | `version_files` | `list` | `[ ]` | Files were the version will be updated. A pattern to match a line, can also be specified, separated by `:` [See more](https://commitizen-tools.github.io/commitizen/bump#files) | | `tag_format` | `str` | `None` | Format for the git tag, useful for old projects, that use a convention like `"v1.2.1"`. [See more](https://commitizen-tools.github.io/commitizen/bump#tag_format) | diff --git a/docs/customization.md b/docs/customization.md index 8419e3d575..bae9f047af 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -6,7 +6,7 @@ The basic steps are: 1. Inheriting from `BaseCommitizen` 2. Give a name to your rules. -3. expose the class at the end of your file assigning it to `discover_this` +3. Expose the class at the end of your file assigning it to `discover_this` 4. Create a python package starting with `cz_` using `setup.py`, `poetry`, etc Check an [example](convcomms) on how to configure `BaseCommitizen`. @@ -21,7 +21,7 @@ See [commitizen_cz_template](https://github.com/commitizen-tools/commitizen_cz_t ### 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] +Create a file starting with `cz_`, for example `cz_jira.py`. This prefix is used to detect the plug-in. Same method [flask uses] Inherit from `BaseCommitizen`, and you must define `questions` and `message`. The others are optional. @@ -73,7 +73,7 @@ class JiraCz(BaseCommitizen): return 'We use this because is useful' -discover_this = JiraCz # used by the plugin system +discover_this = JiraCz # used by the plug-in system ``` The next file required is `setup.py` modified from flask version. @@ -189,7 +189,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. | +| `question` | `dict` | `None` | Questions regarding the commit message. Detailed below. | | `message_template` | `str` | `None` | The template for generating message from the given answers. `message_template` should either follow 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`. | diff --git a/docs/init.md b/docs/init.md index 38a3afd431..a8eb3afa9d 100644 --- a/docs/init.md +++ b/docs/init.md @@ -1,7 +1,7 @@ For new projects, it is possible to run `cz init`. This command will prompt the user for information about the project and will -configure the selected file type (`pyproject.toml`, `.cz.toml`, etc). +configure the selected file type (`pyproject.toml`, `.cz.toml`, etc.). This will help you quickly set up your project with `commitizen`. diff --git a/docs/tutorials/gitlab_ci.md b/docs/tutorials/gitlab_ci.md index 18756d4668..80cbd4028b 100644 --- a/docs/tutorials/gitlab_ci.md +++ b/docs/tutorials/gitlab_ci.md @@ -38,7 +38,7 @@ The latest step is to create a `deploy key.` To do this, we should create it und If you have more projects under the same organization, you can reuse the deploy key created before, but you will have to repeat the step where we have created the environment variables (ssh key, email, and username). -tip: If the CI raise some errors, try to unprotect the private key. +tip: If the CI raise some errors, try to unprotected the private key. #### Defining GitLab CI Pipeline diff --git a/docs/tutorials/writing_commits.md b/docs/tutorials/writing_commits.md index c981df004c..cf6b6bda11 100644 --- a/docs/tutorials/writing_commits.md +++ b/docs/tutorials/writing_commits.md @@ -22,7 +22,7 @@ Not to the important part, when writing commits, it's important to think about: You may think this is trivial, but it's not. It's important for the reader to understand what happened. -### Recomendations +### Recommendations - **Keep the message short**: Makes the list of commits more readable (~50 chars). - **Talk imperative**: Follow this rule: `If applied, this commit will ` From 7d4e3b9781dab9b9a6b27017b9b9ab07fef16043 Mon Sep 17 00:00:00 2001 From: Georgiy Ignatov Date: Fri, 10 Apr 2020 14:55:29 +0300 Subject: [PATCH 021/427] feat(bump): support for ! as BREAKING change in commit message * feat(find_increment): allow to use regex keys for bump_map Default bump_map doesnt consider breaking change identificator "!". Regex keys should take care of it. * test: return check for black and isort * feat(defaults): change default `bump_pattern` and `bump_map` --- commitizen/bump.py | 38 +++++++++++++++++++------------ commitizen/defaults.py | 23 +++++++++++-------- tests/test_bump_find_increment.py | 19 ++++++++++++++-- 3 files changed, 54 insertions(+), 26 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index d9fcbc1564..bb80e2ba6a 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -1,5 +1,5 @@ import re -from collections import defaultdict +from collections import OrderedDict from itertools import zip_longest from string import Template from typing import List, Optional, Union @@ -18,28 +18,36 @@ def find_increment( - commits: List[GitCommit], regex: str = bump_pattern, increments_map: dict = bump_map + commits: List[GitCommit], + regex: str = bump_pattern, + increments_map: Union[dict, OrderedDict] = bump_map, ) -> Optional[str]: + if isinstance(increments_map, dict): + increments_map = OrderedDict(increments_map) + # Most important cases are major and minor. # Everything else will be considered patch. - increments_map_default = defaultdict(lambda: None, increments_map) - pattern = re.compile(regex) + select_pattern = re.compile(regex) increment = None for commit in commits: for message in commit.message.split("\n"): - result = pattern.search(message) - if not result: - continue - found_keyword = result.group(0) - new_increment = increments_map_default[found_keyword] - if increment == "MAJOR": - continue - elif increment == "MINOR" and new_increment == "MAJOR": - increment = new_increment - elif increment == "PATCH" or increment is None: - increment = new_increment + result = select_pattern.search(message) + if result: + found_keyword = result.group(0) + new_increment = None + for match_pattern in increments_map.keys(): + if re.match(match_pattern, found_keyword): + new_increment = increments_map[match_pattern] + break + + if increment == "MAJOR": + continue + elif increment == "MINOR" and new_increment == "MAJOR": + increment = new_increment + elif increment == "PATCH" or increment is None: + increment = new_increment return increment diff --git a/commitizen/defaults.py b/commitizen/defaults.py index 0dfee12246..e38ef01bf0 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -1,10 +1,12 @@ +from collections import OrderedDict + name: str = "cz_conventional_commits" # TODO: .cz, setup.cfg, .cz.cfg should be removed in 2.0 long_term_support_config_files: list = ["pyproject.toml", ".cz.toml"] deprcated_config_files: list = [".cz", "setup.cfg", ".cz.cfg"] config_files: list = long_term_support_config_files + deprcated_config_files -DEFAULT_SETTINGS = { +DEFAULT_SETTINGS: dict = { "name": "cz_conventional_commits", "version": None, "version_files": [], @@ -16,12 +18,15 @@ MINOR = "MINOR" PATCH = "PATCH" -bump_pattern = r"^(BREAKING CHANGE|feat|fix|refactor|perf)" -bump_map = { - "BREAKING CHANGE": MAJOR, - "feat": MINOR, - "fix": PATCH, - "refactor": PATCH, - "perf": PATCH, -} +bump_pattern = r"^(BREAKING[\-\ ]CHANGE|feat|fix|refactor|perf)(\(.+\))?(!)?" +bump_map = OrderedDict( + ( + (r"^.+!$", MAJOR), + (r"^BREAKING[\-\ ]CHANGE", MAJOR), + (r"^feat", MINOR), + (r"^fix", PATCH), + (r"^refactor", PATCH), + (r"^perf", PATCH), + ) +) bump_message = "bump: version $current_version → $new_version" diff --git a/tests/test_bump_find_increment.py b/tests/test_bump_find_increment.py index 5930be078f..1f98694a2b 100644 --- a/tests/test_bump_find_increment.py +++ b/tests/test_bump_find_increment.py @@ -20,13 +20,26 @@ "fix(setup.py): future is now required for every python version", ] -MAJOR_INCREMENTS_CC = [ +MAJOR_INCREMENTS_BREAKING_CHANGE_CC = [ "feat(cli): added version", "docs(README): motivation", "BREAKING CHANGE: `extends` key in config file is now used for extending other config files", # noqa "fix(setup.py): future is now required for every python version", ] +MAJOR_INCREMENTS_BREAKING_CHANGE_ALT_CC = [ + "feat(cli): added version", + "docs(README): motivation", + "BREAKING-CHANGE: `extends` key in config file is now used for extending other config files", # noqa + "fix(setup.py): future is now required for every python version", +] + +MAJOR_INCREMENTS_EXCLAMATION_CC = [ + "feat(cli)!: added version", + "docs(README): motivation", + "fix(setup.py): future is now required for every python version", +] + PATCH_INCREMENTS_SVE = ["readme motivation PATCH", "fix setup.py PATCH"] MINOR_INCREMENTS_SVE = [ @@ -51,7 +64,9 @@ ( (PATCH_INCREMENTS_CC, "PATCH"), (MINOR_INCREMENTS_CC, "MINOR"), - (MAJOR_INCREMENTS_CC, "MAJOR"), + (MAJOR_INCREMENTS_BREAKING_CHANGE_CC, "MAJOR"), + (MAJOR_INCREMENTS_BREAKING_CHANGE_ALT_CC, "MAJOR"), + (MAJOR_INCREMENTS_EXCLAMATION_CC, "MAJOR"), (NONE_INCREMENT_CC, None), ), ) From 25e8f7e7271ca7476306784b2a64214c9c0417bc Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Wed, 8 Apr 2020 18:51:00 +0800 Subject: [PATCH 022/427] style(mypy): unify config path input as Union[str, Path] and output as Path --- commitizen/config/__init__.py | 2 +- commitizen/config/base_config.py | 11 ++++++----- commitizen/config/ini_config.py | 4 +++- commitizen/config/toml_config.py | 5 ++++- commitizen/defaults.py | 3 ++- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/commitizen/config/__init__.py b/commitizen/config/__init__.py index 9b317f1e36..3a729e4be5 100644 --- a/commitizen/config/__init__.py +++ b/commitizen/config/__init__.py @@ -29,7 +29,7 @@ def load_global_conf() -> Optional[IniConfig]: with open(global_cfg, "r") as f: data = f.read() - conf = IniConfig(data) + conf = IniConfig(data=data, path=global_cfg) return conf diff --git a/commitizen/config/base_config.py b/commitizen/config/base_config.py index 7f5951d790..327a7dc9b1 100644 --- a/commitizen/config/base_config.py +++ b/commitizen/config/base_config.py @@ -1,5 +1,6 @@ import warnings -from typing import Optional +from typing import Optional, Union +from pathlib import Path from commitizen.defaults import DEFAULT_SETTINGS @@ -7,14 +8,14 @@ class BaseConfig: def __init__(self): self._settings: dict = DEFAULT_SETTINGS.copy() - self._path: Optional[str] = None + self._path: Optional[Path] = None @property def settings(self) -> dict: return self._settings @property - def path(self) -> str: + def path(self) -> Optional[Path]: return self._path def set_key(self, key, value): @@ -28,8 +29,8 @@ def set_key(self, key, value): def update(self, data: dict): self._settings.update(data) - def add_path(self, path: str): - self._path = path + def add_path(self, path: Union[str, Path]): + self._path = Path(path) def _parse_setting(self, data: str) -> dict: raise NotImplementedError() diff --git a/commitizen/config/ini_config.py b/commitizen/config/ini_config.py index 39f7488bc4..88544f9b79 100644 --- a/commitizen/config/ini_config.py +++ b/commitizen/config/ini_config.py @@ -1,12 +1,14 @@ import configparser import json import warnings +from pathlib import Path +from typing import Optional, Union from .base_config import BaseConfig class IniConfig(BaseConfig): - def __init__(self, *, data: str, path: str): + def __init__(self, *, data: str, path: Union[Path, str]): warnings.simplefilter("always", DeprecationWarning) warnings.warn( ( diff --git a/commitizen/config/toml_config.py b/commitizen/config/toml_config.py index 21ffd62e8d..f075091ba3 100644 --- a/commitizen/config/toml_config.py +++ b/commitizen/config/toml_config.py @@ -1,10 +1,13 @@ +from typing import Optional, Union +from pathlib import Path + from tomlkit import exceptions, parse from .base_config import BaseConfig class TomlConfig(BaseConfig): - def __init__(self, *, data: str, path: str): + def __init__(self, *, data: str, path: Union[Path, str]): super(TomlConfig, self).__init__() self.is_empty_config = False self._parse_setting(data) diff --git a/commitizen/defaults.py b/commitizen/defaults.py index e38ef01bf0..2f4fae78b2 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -1,4 +1,5 @@ from collections import OrderedDict +from typing import Dict, Any name: str = "cz_conventional_commits" # TODO: .cz, setup.cfg, .cz.cfg should be removed in 2.0 @@ -6,7 +7,7 @@ deprcated_config_files: list = [".cz", "setup.cfg", ".cz.cfg"] config_files: list = long_term_support_config_files + deprcated_config_files -DEFAULT_SETTINGS: dict = { +DEFAULT_SETTINGS: Dict[str, Any] = { "name": "cz_conventional_commits", "version": None, "version_files": [], From e0a2ff084457b13dabc633223c1f04c12f39ee5a Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Wed, 8 Apr 2020 19:08:18 +0800 Subject: [PATCH 023/427] refactor(config): fix mypy warning for _conf --- commitizen/config/__init__.py | 3 ++- commitizen/config/base_config.py | 2 +- commitizen/config/toml_config.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/commitizen/config/__init__.py b/commitizen/config/__init__.py index 3a729e4be5..48a61c75fd 100644 --- a/commitizen/config/__init__.py +++ b/commitizen/config/__init__.py @@ -1,6 +1,6 @@ import warnings from pathlib import Path -from typing import Optional +from typing import Optional, Union from commitizen import defaults, git, out from commitizen.error_codes import NOT_A_GIT_PROJECT @@ -56,6 +56,7 @@ def read_cfg() -> BaseConfig: with open(filename, "r") as f: data: str = f.read() + _conf: Union[TomlConfig, IniConfig] if "toml" in filename.suffix: _conf = TomlConfig(data=data, path=filename) else: diff --git a/commitizen/config/base_config.py b/commitizen/config/base_config.py index 327a7dc9b1..5392ac6272 100644 --- a/commitizen/config/base_config.py +++ b/commitizen/config/base_config.py @@ -1,6 +1,6 @@ import warnings -from typing import Optional, Union from pathlib import Path +from typing import Optional, Union from commitizen.defaults import DEFAULT_SETTINGS diff --git a/commitizen/config/toml_config.py b/commitizen/config/toml_config.py index f075091ba3..000502c687 100644 --- a/commitizen/config/toml_config.py +++ b/commitizen/config/toml_config.py @@ -1,5 +1,5 @@ -from typing import Optional, Union from pathlib import Path +from typing import Optional, Union from tomlkit import exceptions, parse From ded92b2df383e97f61d12a4dcbf46efe2b9f18c8 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Wed, 8 Apr 2020 19:15:22 +0800 Subject: [PATCH 024/427] refactor(cz): add type annotation for each function in cz --- commitizen/cz/__init__.py | 2 +- commitizen/cz/base.py | 8 ++++---- .../conventional_commits.py | 5 +++-- commitizen/cz/customize/customize.py | 17 ++++++++++------- commitizen/cz/jira/jira.py | 12 +++++++----- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/commitizen/cz/__init__.py b/commitizen/cz/__init__.py index 3c379f3c6b..c8c988bba6 100644 --- a/commitizen/cz/__init__.py +++ b/commitizen/cz/__init__.py @@ -11,7 +11,7 @@ "cz_customize": CustomizeCommitsCz, } plugins = { - name: importlib.import_module(name).discover_this + name: importlib.import_module(name).discover_this # type: ignore for finder, name, ispkg in pkgutil.iter_modules() if name.startswith("cz_") } diff --git a/commitizen/cz/base.py b/commitizen/cz/base.py index 258f43ca5e..32ac9f812c 100644 --- a/commitizen/cz/base.py +++ b/commitizen/cz/base.py @@ -42,18 +42,18 @@ def style(self): ] ) - def example(self) -> str: + def example(self) -> Optional[str]: """Example of the commit message.""" raise NotImplementedError("Not Implemented yet") - def schema(self) -> str: + def schema(self) -> Optional[str]: """Schema definition of the commit message.""" raise NotImplementedError("Not Implemented yet") - def schema_pattern(self) -> str: + def schema_pattern(self) -> Optional[str]: """Regex matching the schema used for message validation""" raise NotImplementedError("Not Implemented yet") - def info(self) -> str: + def info(self) -> Optional[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 a9bfcf2039..fc4bef9792 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -1,4 +1,5 @@ import os +from typing import List, Dict, Any from commitizen import defaults from commitizen.cz.base import BaseCommitizen @@ -29,8 +30,8 @@ class ConventionalCommitsCz(BaseCommitizen): bump_pattern = defaults.bump_pattern bump_map = defaults.bump_map - def questions(self) -> list: - questions = [ + def questions(self) -> List[Dict[str, Any]]: + questions: List[Dict[str, Any]] = [ { "type": "list", "name": "prefix", diff --git a/commitizen/cz/customize/customize.py b/commitizen/cz/customize/customize.py index 1e10975fe8..7eb38bcd8d 100644 --- a/commitizen/cz/customize/customize.py +++ b/commitizen/cz/customize/customize.py @@ -1,7 +1,9 @@ try: - from jinja2 import Template + from jinja2 import Template # type: ignore except ImportError: - from string import Template + from string import Template # type: ignore + +from typing import Optional, List, Any, Dict from commitizen import defaults from commitizen.config import BaseConfig @@ -26,23 +28,23 @@ def __init__(self, config: BaseConfig): if custom_bump_map: self.bump_map = custom_bump_map - def questions(self) -> list: + def questions(self) -> List[Dict[str, Any]]: return self.custom_settings.get("questions") def message(self, answers: dict) -> str: message_template = Template(self.custom_settings.get("message_template")) if getattr(Template, "substitute", None): - return message_template.substitute(**answers) + return message_template.substitute(**answers) # type: ignore else: return message_template.render(**answers) - def example(self) -> str: + def example(self) -> Optional[str]: return self.custom_settings.get("example") - def schema(self) -> str: + def schema(self) -> Optional[str]: return self.custom_settings.get("schema") - def info(self) -> str: + def info(self) -> Optional[str]: info_path = self.custom_settings.get("info_path") info = self.custom_settings.get("info") if info_path: @@ -51,3 +53,4 @@ def info(self) -> str: return content elif info: return info + return None diff --git a/commitizen/cz/jira/jira.py b/commitizen/cz/jira/jira.py index b853855fba..3c35b50254 100644 --- a/commitizen/cz/jira/jira.py +++ b/commitizen/cz/jira/jira.py @@ -1,12 +1,14 @@ import os +from typing import List, Dict, Any + from commitizen.cz.base import BaseCommitizen __all__ = ["JiraSmartCz"] class JiraSmartCz(BaseCommitizen): - def questions(self): + def questions(self) -> List[Dict[str, Any]]: questions = [ { "type": "input", @@ -43,7 +45,7 @@ def questions(self): ] return questions - def message(self, answers): + def message(self, answers) -> str: return " ".join( filter( bool, @@ -57,7 +59,7 @@ def message(self, answers): ) ) - def example(self): + def example(self) -> str: return ( "JRA-34 #comment corrected indent issue\n" "JRA-35 #time 1w 2d 4h 30m Total work logged\n" @@ -66,13 +68,13 @@ def example(self): "ahead of schedule" ) - def schema(self): + def schema(self) -> str: return " # " # noqa def schema_pattern(self) -> str: return r".*[A-Z]{2,}\-[0-9]+( #| .* #).+( #.+)*" - def info(self): + def info(self) -> str: dir_path = os.path.dirname(os.path.realpath(__file__)) filepath = os.path.join(dir_path, "jira_info.txt") with open(filepath, "r") as f: From a6dde29bbd328a455ed6616d0341e0b1dde4e9b4 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 9 Apr 2020 16:42:52 +0800 Subject: [PATCH 025/427] refactor(cz/base): fix config type used in base cz --- commitizen/cz/base.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/commitizen/cz/base.py b/commitizen/cz/base.py index 32ac9f812c..cd0775e6f7 100644 --- a/commitizen/cz/base.py +++ b/commitizen/cz/base.py @@ -3,6 +3,8 @@ from prompt_toolkit.styles import Style, merge_styles +from commitizen.config.base_config import BaseConfig + class BaseCommitizen(metaclass=ABCMeta): bump_pattern: Optional[str] = None @@ -20,7 +22,7 @@ class BaseCommitizen(metaclass=ABCMeta): ("disabled", "fg:#858585 italic"), ] - def __init__(self, config: dict): + def __init__(self, config: BaseConfig): self.config = config if not self.config.settings.get("style"): self.config.settings.update({"style": BaseCommitizen.default_style_config}) From 5fad7b75f8643a2f39138f87737c025c4f85b57d Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 9 Apr 2020 16:43:23 +0800 Subject: [PATCH 026/427] refactor(config/base): use Dict to replace dict in base_config --- commitizen/config/base_config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/commitizen/config/base_config.py b/commitizen/config/base_config.py index 5392ac6272..e01ed2d5f4 100644 --- a/commitizen/config/base_config.py +++ b/commitizen/config/base_config.py @@ -1,17 +1,17 @@ import warnings from pathlib import Path -from typing import Optional, Union +from typing import Optional, Union, Dict, Any from commitizen.defaults import DEFAULT_SETTINGS class BaseConfig: def __init__(self): - self._settings: dict = DEFAULT_SETTINGS.copy() + self._settings: Dict[str, Any] = DEFAULT_SETTINGS.copy() self._path: Optional[Path] = None @property - def settings(self) -> dict: + def settings(self) -> Dict[str, Any]: return self._settings @property From cdfe112d373cd20dff6da9dacb3b13de9a7507e6 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 9 Apr 2020 16:44:05 +0800 Subject: [PATCH 027/427] refactor(commands/check): fix type annotation --- commitizen/commands/check.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py index 830cb6bb85..ccfb7a4791 100644 --- a/commitizen/commands/check.py +++ b/commitizen/commands/check.py @@ -1,6 +1,6 @@ import os import re -from typing import Dict +from typing import Dict, Optional from commitizen import factory, git, out from commitizen.config import BaseConfig @@ -22,8 +22,8 @@ def __init__(self, config: BaseConfig, arguments: Dict[str, str], cwd=os.getcwd( the flags provided by the user """ - self.commit_msg_file: str = arguments.get("commit_msg_file") - self.rev_range: str = arguments.get("rev_range") + self.commit_msg_file: Optional[str] = arguments.get("commit_msg_file") + self.rev_range: Optional[str] = arguments.get("rev_range") self._valid_command_argument() @@ -76,4 +76,4 @@ def _get_commit_messages(self): def validate_commit_message(commit_msg: str, pattern: str) -> bool: if commit_msg.startswith("Merge") or commit_msg.startswith("Revert"): return True - return re.match(pattern, commit_msg) + return bool(re.match(pattern, commit_msg)) From c4b1591595c463cbdbf80b354d8d7bc00b4f4fc9 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 9 Apr 2020 16:44:43 +0800 Subject: [PATCH 028/427] fix(cz/customize): add error handling when customize detail is not set --- commitizen/cz/customize/customize.py | 10 +++++++++- commitizen/error_codes.py | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/commitizen/cz/customize/customize.py b/commitizen/cz/customize/customize.py index 7eb38bcd8d..797efbabee 100644 --- a/commitizen/cz/customize/customize.py +++ b/commitizen/cz/customize/customize.py @@ -7,7 +7,9 @@ from commitizen import defaults from commitizen.config import BaseConfig +from commitizen import out from commitizen.cz.base import BaseCommitizen +from commitizen.error_codes import MISSING_CONFIG __all__ = ["CustomizeCommitsCz"] @@ -18,7 +20,13 @@ class CustomizeCommitsCz(BaseCommitizen): def __init__(self, config: BaseConfig): super(CustomizeCommitsCz, self).__init__(config) - self.custom_settings = self.config.settings.get("customize") + + if "customize" not in self.config.settings: + out.error( + "fatal: customize is not set in configuration file." + ) + raise SystemExit(MISSING_CONFIG) + self.custom_settings = self.config.settings["customize"] custom_bump_pattern = self.custom_settings.get("bump_pattern") if custom_bump_pattern: diff --git a/commitizen/error_codes.py b/commitizen/error_codes.py index c6eeac7a27..20cc54aa9e 100644 --- a/commitizen/error_codes.py +++ b/commitizen/error_codes.py @@ -3,6 +3,7 @@ # Config NOT_A_GIT_PROJECT = 2 +MISSING_CONFIG = 15 # Bump NO_COMMITS_FOUND = 3 From 28949ea9948067f49685c5af11ec0b1b485121bd Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 9 Apr 2020 16:45:13 +0800 Subject: [PATCH 029/427] style: reformat --- commitizen/config/base_config.py | 2 +- .../cz/conventional_commits/conventional_commits.py | 2 +- commitizen/cz/customize/customize.py | 9 +++------ commitizen/cz/jira/jira.py | 3 +-- commitizen/defaults.py | 2 +- 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/commitizen/config/base_config.py b/commitizen/config/base_config.py index e01ed2d5f4..f5febf3d34 100644 --- a/commitizen/config/base_config.py +++ b/commitizen/config/base_config.py @@ -1,6 +1,6 @@ import warnings from pathlib import Path -from typing import Optional, Union, Dict, Any +from typing import Any, Dict, Optional, Union from commitizen.defaults import DEFAULT_SETTINGS diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index fc4bef9792..fcf0df4b58 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -1,5 +1,5 @@ import os -from typing import List, Dict, Any +from typing import Any, Dict, List from commitizen import defaults from commitizen.cz.base import BaseCommitizen diff --git a/commitizen/cz/customize/customize.py b/commitizen/cz/customize/customize.py index 797efbabee..c3bc7a048b 100644 --- a/commitizen/cz/customize/customize.py +++ b/commitizen/cz/customize/customize.py @@ -3,11 +3,10 @@ except ImportError: from string import Template # type: ignore -from typing import Optional, List, Any, Dict +from typing import Any, Dict, List, Optional -from commitizen import defaults +from commitizen import defaults, out from commitizen.config import BaseConfig -from commitizen import out from commitizen.cz.base import BaseCommitizen from commitizen.error_codes import MISSING_CONFIG @@ -22,9 +21,7 @@ def __init__(self, config: BaseConfig): super(CustomizeCommitsCz, self).__init__(config) if "customize" not in self.config.settings: - out.error( - "fatal: customize is not set in configuration file." - ) + out.error("fatal: customize is not set in configuration file.") raise SystemExit(MISSING_CONFIG) self.custom_settings = self.config.settings["customize"] diff --git a/commitizen/cz/jira/jira.py b/commitizen/cz/jira/jira.py index 3c35b50254..46c5965c46 100644 --- a/commitizen/cz/jira/jira.py +++ b/commitizen/cz/jira/jira.py @@ -1,6 +1,5 @@ import os - -from typing import List, Dict, Any +from typing import Any, Dict, List from commitizen.cz.base import BaseCommitizen diff --git a/commitizen/defaults.py b/commitizen/defaults.py index 2f4fae78b2..477a48e4a1 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -1,5 +1,5 @@ from collections import OrderedDict -from typing import Dict, Any +from typing import Any, Dict name: str = "cz_conventional_commits" # TODO: .cz, setup.cfg, .cz.cfg should be removed in 2.0 From 9c12b9fbd3e1d8f14b9ba7b542c75f5fe1fee828 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 9 Apr 2020 17:03:45 +0800 Subject: [PATCH 030/427] refactor(cz): add type annotation to registry --- commitizen/cz/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/commitizen/cz/__init__.py b/commitizen/cz/__init__.py index c8c988bba6..a14ea95edf 100644 --- a/commitizen/cz/__init__.py +++ b/commitizen/cz/__init__.py @@ -1,11 +1,13 @@ import importlib import pkgutil +from typing import Dict, Type +from commitizen.cz.base import BaseCommitizen from commitizen.cz.conventional_commits import ConventionalCommitsCz from commitizen.cz.customize import CustomizeCommitsCz from commitizen.cz.jira import JiraSmartCz -registry = { +registry: Dict[str, Type[BaseCommitizen]] = { "cz_conventional_commits": ConventionalCommitsCz, "cz_jira": JiraSmartCz, "cz_customize": CustomizeCommitsCz, From db8e37ec8b3611010a2dfba4b8c82c00c6abce57 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 9 Apr 2020 17:06:55 +0800 Subject: [PATCH 031/427] style(config): move .flake8 to setup.cfg and add mypy, pytest config --- .flake8 | 4 ---- setup.cfg | 28 ++++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) delete mode 100644 .flake8 create mode 100644 setup.cfg diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 73998f1162..0000000000 --- a/.flake8 +++ /dev/null @@ -1,4 +0,0 @@ -[flake8] -exclude = .git,__pycache__,docs/source/conf.py,old,build,dist -max-complexity = 10 -max-line-length = 100 diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000000..53860b52a0 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,28 @@ +[tool:pytest] +addopts = --strict-markers +norecursedirs = .* build dist CVS _darcs {arch} *.egg venv env virtualenv + + +[mypy] +files = commitizen, tests +ignore_missing_imports = true + + +[flake8] +ignore = + # F632: use ==/!= to compare str, bytes, and int literals + F632, + # W503: Line break occurred before a binary operator + W503, + # E501: Line too long + E501, + # E203: Whitespace before ':' (for black) + E203 +exclude = + .git, + __pycache__, + docs/source/conf.py, + build, + dist +max-line-length = 88 +max-complexity = 10 From 2754a34ddd79dec68a854d8cbb38d096cb7fc409 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 9 Apr 2020 17:10:27 +0800 Subject: [PATCH 032/427] ci(scripts/test): remove redundant arugment (it's been configed in setup.cfg) --- scripts/test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test b/scripts/test index 6a8082162e..768c000a31 100755 --- a/scripts/test +++ b/scripts/test @@ -8,4 +8,4 @@ fi ${PREFIX}pytest --cov-report term-missing --cov-report=xml:coverage.xml --cov=commitizen tests/ ${PREFIX}black commitizen tests --check ${PREFIX}isort --recursive --check-only commitizen tests -${PREFIX}flake8 --max-line-length=88 commitizen/ tests/ +${PREFIX}flake8 commitizen/ tests/ From c59929577be8ec9aaca6c94ead8a566b431281c4 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 9 Apr 2020 17:11:48 +0800 Subject: [PATCH 033/427] ci(scripts/test): add mypy check --- scripts/test | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/test b/scripts/test index 768c000a31..86c1669a10 100755 --- a/scripts/test +++ b/scripts/test @@ -9,3 +9,4 @@ ${PREFIX}pytest --cov-report term-missing --cov-report=xml:coverage.xml --cov=co ${PREFIX}black commitizen tests --check ${PREFIX}isort --recursive --check-only commitizen tests ${PREFIX}flake8 commitizen/ tests/ +${PREFIX}mypy commitizen/ tests/ From 65edcc3be8d73fc52fc2eee0fe5d85b50889ce8b Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 9 Apr 2020 17:41:15 +0800 Subject: [PATCH 034/427] style: remove unused import --- commitizen/config/ini_config.py | 2 +- commitizen/config/toml_config.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/commitizen/config/ini_config.py b/commitizen/config/ini_config.py index 88544f9b79..6ac003ad46 100644 --- a/commitizen/config/ini_config.py +++ b/commitizen/config/ini_config.py @@ -2,7 +2,7 @@ import json import warnings from pathlib import Path -from typing import Optional, Union +from typing import Union from .base_config import BaseConfig diff --git a/commitizen/config/toml_config.py b/commitizen/config/toml_config.py index 000502c687..e13d720a17 100644 --- a/commitizen/config/toml_config.py +++ b/commitizen/config/toml_config.py @@ -1,5 +1,5 @@ from pathlib import Path -from typing import Optional, Union +from typing import Union from tomlkit import exceptions, parse From 2738b740f7e220278e3ef7677379627c88ccdc61 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 9 Apr 2020 17:58:50 +0800 Subject: [PATCH 035/427] refactor(mypy): fix mypy check by checking version.pre exists --- commitizen/bump.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index bb80e2ba6a..171accbd44 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -66,10 +66,12 @@ def prerelease_generator(current_version: str, prerelease: Optional[str] = None) return "" version = Version(current_version) - new_prerelease_number: int = 0 - if version.is_prerelease and prerelease.startswith(version.pre[0]): - prev_prerelease: int = list(version.pre)[1] + # version.pre is needed for mypy check + if version.is_prerelease and version.pre and prerelease.startswith(version.pre[0]): + prev_prerelease: int = version.pre[1] new_prerelease_number = prev_prerelease + 1 + else: + new_prerelease_number = 0 pre_version = f"{prerelease}{new_prerelease_number}" return pre_version @@ -176,7 +178,8 @@ def create_tag(version: Union[Version, str], tag_format: Optional[str] = None): major, minor, patch = version.release prerelease = "" - if version.is_prerelease: + # version.pre is needed for mypy check + if version.is_prerelease and version.pre: prerelease = f"{version.pre[0]}{version.pre[1]}" t = Template(tag_format) From 495525791ea48c6e431ef2572dfe9fff902d1f10 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 9 Apr 2020 18:13:52 +0800 Subject: [PATCH 036/427] refactor(cz/customize): remove unused mypy ignore --- commitizen/cz/customize/customize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commitizen/cz/customize/customize.py b/commitizen/cz/customize/customize.py index c3bc7a048b..28d1b13738 100644 --- a/commitizen/cz/customize/customize.py +++ b/commitizen/cz/customize/customize.py @@ -1,5 +1,5 @@ try: - from jinja2 import Template # type: ignore + from jinja2 import Template except ImportError: from string import Template # type: ignore From 582f2a23c6d7c7db1a0861b46284c31a18883d9e Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 9 Apr 2020 18:14:24 +0800 Subject: [PATCH 037/427] ci(mypy-config): add stricter config but comment out those we not yet follow --- setup.cfg | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/setup.cfg b/setup.cfg index 53860b52a0..ac1f11ee38 100644 --- a/setup.cfg +++ b/setup.cfg @@ -6,6 +6,16 @@ norecursedirs = .* build dist CVS _darcs {arch} *.egg venv env virtualenv [mypy] files = commitizen, tests ignore_missing_imports = true +# disallow_untyped_calls = True +# disallow_untyped_defs = True +# disallow_incomplete_defs = True +disallow_untyped_decorators = True +# disallow_any_generics = True +disallow_subclassing_any = True +# warn_return_any = True +warn_redundant_casts = True +warn_unused_ignores = True +warn_unused_configs = True [flake8] From 906d1fb4180eb692397323506dcb292bb8f84232 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 9 Apr 2020 18:35:42 +0800 Subject: [PATCH 038/427] test(cz/customize): add test case initialize_cz_customize_failed --- tests/test_cz_customize.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py index 3ec448cc32..3cc76eb9e0 100644 --- a/tests/test_cz_customize.py +++ b/tests/test_cz_customize.py @@ -1,7 +1,8 @@ import pytest -from commitizen.config import TomlConfig +from commitizen.config import BaseConfig, TomlConfig from commitizen.cz.customize import CustomizeCommitsCz +from commitizen.error_codes import MISSING_CONFIG @pytest.fixture(scope="module") @@ -37,6 +38,14 @@ def config(): return TomlConfig(data=toml_str, path="not_exist.toml") +def test_initialize_cz_customize_failed(): + with pytest.raises(SystemExit) as excinfo: + config = BaseConfig() + _ = CustomizeCommitsCz(config) + + assert excinfo.value.code == MISSING_CONFIG + + def test_bump_pattern(config): cz = CustomizeCommitsCz(config) assert cz.bump_pattern == "^(break|new|fix|hotfix)" From 400b35bf08def8b31ea552f7f3cce84b31297c05 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 13 Apr 2020 09:56:22 +0000 Subject: [PATCH 039/427] =?UTF-8?q?bump:=20version=201.17.1=20=E2=86=92=20?= =?UTF-8?q?1.18.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 c7bbe49657..6cea18d86c 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.17.1" +__version__ = "1.18.0" diff --git a/pyproject.toml b/pyproject.toml index b5b4560657..08ec881643 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.17.1" +version = "1.18.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.17.1" +version = "1.18.0" description = "Python commitizen client tool" authors = ["Santiago Fraire "] license = "MIT" From 977f98cd921b0fb3ba6e4db6ac01aab02a4a098d Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 16 Apr 2020 15:29:19 +0800 Subject: [PATCH 040/427] fix(config): display ini config deprecation warning only when commitizen config is inside #159 --- commitizen/config/__init__.py | 8 +------- commitizen/config/ini_config.py | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/commitizen/config/__init__.py b/commitizen/config/__init__.py index 48a61c75fd..b0dbd7bdc4 100644 --- a/commitizen/config/__init__.py +++ b/commitizen/config/__init__.py @@ -43,11 +43,10 @@ def read_cfg() -> BaseConfig: ) raise SystemExit(NOT_A_GIT_PROJECT) - allowed_cfg_files = defaults.config_files cfg_paths = ( path / Path(filename) for path in [Path("."), git_project_root] - for filename in allowed_cfg_files + for filename in defaults.config_files ) for filename in cfg_paths: if not filename.exists(): @@ -60,11 +59,6 @@ def read_cfg() -> BaseConfig: if "toml" in filename.suffix: _conf = TomlConfig(data=data, path=filename) else: - warnings.warn( - ".cz, setup.cfg, and .cz.cfg will be deprecated " - "in next major version. \n" - 'Please use "pyproject.toml", ".cz.toml" instead' - ) _conf = IniConfig(data=data, path=filename) if _conf.is_empty_config: diff --git a/commitizen/config/ini_config.py b/commitizen/config/ini_config.py index 6ac003ad46..78274123db 100644 --- a/commitizen/config/ini_config.py +++ b/commitizen/config/ini_config.py @@ -9,16 +9,6 @@ class IniConfig(BaseConfig): def __init__(self, *, data: str, path: Union[Path, str]): - warnings.simplefilter("always", DeprecationWarning) - warnings.warn( - ( - ".cz, setup.cfg, and .cz.cfg will be deprecated " - "in next major version. \n" - 'Please use "pyproject.toml", ".cz.toml" instead' - ), - category=DeprecationWarning, - ) - super(IniConfig, self).__init__() self.is_empty_config = False self._parse_setting(data) @@ -74,3 +64,13 @@ def _parse_setting(self, data: str): self._settings.update(_data) except KeyError: self.is_empty_config = True + else: + warnings.simplefilter("always", DeprecationWarning) + warnings.warn( + ( + ".cz, setup.cfg, and .cz.cfg will be deprecated " + "in next major version. \n" + 'Please use "pyproject.toml", ".cz.toml" instead' + ), + category=DeprecationWarning, + ) From c1d780c67686e5d894eadfef03f23e940a9af8b0 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 16 Apr 2020 15:40:30 +0800 Subject: [PATCH 041/427] test(conf): add test case for reading setup.cfg with empty config --- tests/test_conf.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_conf.py b/tests/test_conf.py index 277234e5e5..58580e52a6 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -142,6 +142,13 @@ def test_read_cfg_when_not_in_a_git_project(tmpdir): config.read_cfg() +class TestInilConfig: + def test_read_setup_cfg_without_commitizen_config(self, tmpdir): + path = tmpdir.mkdir("commitizen").join("setup.cfg") + ini_config = config.IniConfig(data="", path=path) + assert ini_config.is_empty_config + + class TestTomlConfig: def test_init_empty_config_content(self, tmpdir): path = tmpdir.mkdir("commitizen").join(".cz.toml") From c8bd2f024d3405589d05d53641984d7ecce05e69 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 16 Apr 2020 07:43:37 +0000 Subject: [PATCH 042/427] =?UTF-8?q?bump:=20version=201.18.0=20=E2=86=92=20?= =?UTF-8?q?1.18.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 6cea18d86c..4a7bff5447 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.18.0" +__version__ = "1.18.1" diff --git a/pyproject.toml b/pyproject.toml index 08ec881643..38f69fca9a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.18.0" +version = "1.18.1" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.18.0" +version = "1.18.1" description = "Python commitizen client tool" authors = ["Santiago Fraire "] license = "MIT" From de6a25ec34cbce0550730b407b0a274a4a622129 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Mon, 20 Apr 2020 12:38:55 +0800 Subject: [PATCH 043/427] docs(tutorial/github_actions): suggest using pypi api token #161 --- docs/tutorials/github_actions.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/tutorials/github_actions.md b/docs/tutorials/github_actions.md index 409428d1bc..234c4cc50d 100644 --- a/docs/tutorials/github_actions.md +++ b/docs/tutorials/github_actions.md @@ -56,10 +56,13 @@ Push to master and that's it. Once the new tag is created, triggering an automatic publish command would be desired. -In order to do so, the first two secrets need to be added with the information -of our pypi account. +In order to do so, the crendetial needs 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`. +Instead of using username and password, we suggest using [api token](https://pypi.org/help/#apitoken) generated from PyPI. + +After generate api token, use the token as the PyPI password and `__token__` as the username. + +Go to `Settings > Secrets > Add new secret` and add the secret: `PYPI_PASSWORD`. Create a file in `.github/workflows/pythonpublish.yaml` with the following content: @@ -87,13 +90,12 @@ jobs: poetry install - name: Build and publish env: - PYPI_USERNAME: ${{ secrets.PYPI_USERNAME }} + PYPI_USERNAME: __token__ 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/commitizen-tools/commitizen/blob/master/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/commitizen-tools/commitizen/blob/master/scripts/publish) Push the changes and that's it. From d1cac309270b30f3b26dc3aec91e72a62ee824f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= Date: Sat, 20 Jul 2019 13:01:07 +0200 Subject: [PATCH 044/427] feat(changelog): changelog tree generation from markdown --- commitizen/changelog.py | 133 +++++++++++++++++++++ commitizen/cli.py | 5 + commitizen/commands/__init__.py | 4 + commitizen/commands/changelog.py | 14 +++ tests/test_changelog.py | 199 +++++++++++++++++++++++++++++++ 5 files changed, 355 insertions(+) create mode 100644 commitizen/changelog.py create mode 100644 commitizen/commands/changelog.py create mode 100644 tests/test_changelog.py diff --git a/commitizen/changelog.py b/commitizen/changelog.py new file mode 100644 index 0000000000..495a4513c4 --- /dev/null +++ b/commitizen/changelog.py @@ -0,0 +1,133 @@ +""" +# DESIGN + +## Parse CHANGELOG.md + +1. Get LATEST VERSION from CONFIG +1. Parse the file version to version +2. Build a dict (tree) of that particular version +3. Transform tree into markdown again + +## Parse git log + +1. get commits between versions +2. filter commits with the current cz rules +3. parse commit information +4. generate tree + +Options: +- Generate full or partial changelog +""" +from typing import Generator, List, Dict, Iterable +import re + +MD_VERSION_RE = r"^##\s(?P[a-zA-Z0-9.+]+)\s?\(?(?P[0-9-]+)?\)?" +MD_CATEGORY_RE = r"^###\s(?P[a-zA-Z0-9.+\s]+)" +MD_MESSAGE_RE = r"^-\s(\*{2}(?P[a-zA-Z0-9]+)\*{2}:\s)?(?P.+)" +md_version_c = re.compile(MD_VERSION_RE) +md_category_c = re.compile(MD_CATEGORY_RE) +md_message_c = re.compile(MD_MESSAGE_RE) + + +CATEGORIES = [ + ("fix", "fix"), + ("breaking", "BREAKING CHANGES"), + ("feat", "feat"), + ("refactor", "refactor"), + ("perf", "perf"), + ("test", "test"), + ("build", "build"), + ("ci", "ci"), + ("chore", "chore"), +] + + +def find_version_blocks(filepath: str) -> Generator: + """ + version block: contains all the information about a version. + + E.g: + ``` + ## 1.2.1 (2019-07-20) + + ## Bug fixes + + - username validation not working + + ## Features + + - new login system + + ``` + """ + with open(filepath, "r") as f: + block: list = [] + for line in f: + line = line.strip("\n") + if not line: + continue + + if line.startswith("## "): + if len(block) > 0: + yield block + block = [line] + else: + block.append(line) + yield block + + +def parse_md_version(md_version: str) -> Dict: + m = md_version_c.match(md_version) + if not m: + return {} + return m.groupdict() + + +def parse_md_category(md_category: str) -> Dict: + m = md_category_c.match(md_category) + if not m: + return {} + return m.groupdict() + + +def parse_md_message(md_message: str) -> Dict: + m = md_message_c.match(md_message) + if not m: + return {} + return m.groupdict() + + +def transform_category(category: str) -> str: + _category_lower = category.lower() + for match_value, output in CATEGORIES: + if re.search(match_value, _category_lower): + return output + else: + raise ValueError(f"Could not match a category with {category}") + + +def generate_block_tree(block: List[str]) -> Dict: + tree: Dict = {"commits": []} + category = None + for line in block: + if line.startswith("## "): + category = None + tree = {**tree, **parse_md_version(line)} + elif line.startswith("### "): + result = parse_md_category(line) + if not result: + continue + category = transform_category(result.get("category", "")) + + elif line.startswith("- "): + commit = parse_md_message(line) + commit["category"] = category + tree["commits"].append(commit) + else: + print("it's something else: ", line) + return tree + + +def generate_full_tree(blocks: Iterable) -> Iterable[Dict]: + for block in blocks: + yield generate_block_tree(block) diff --git a/commitizen/cli.py b/commitizen/cli.py index 4ea45d431b..352e83f93f 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -38,6 +38,11 @@ "help": "show available commitizens", "func": commands.ListCz, }, + { + "name": ["changelog", "ch"], + "help": "create new changelog", + "func": commands.Changelog, + }, { "name": ["commit", "c"], "help": "create new commit", diff --git a/commitizen/commands/__init__.py b/commitizen/commands/__init__.py index b87906d8b4..6d1d8a13e5 100644 --- a/commitizen/commands/__init__.py +++ b/commitizen/commands/__init__.py @@ -7,11 +7,15 @@ from .list_cz import ListCz from .schema import Schema from .version import Version +from .init import Init +from .changelog import Changelog + __all__ = ( "Bump", "Check", "Commit", + "Changelog" "Example", "Info", "ListCz", diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py new file mode 100644 index 0000000000..f859292125 --- /dev/null +++ b/commitizen/commands/changelog.py @@ -0,0 +1,14 @@ +from commitizen import factory, out, changelog + + +class Changelog: + """Generate a changelog based on the commit history.""" + + def __init__(self, config: dict, *args): + self.config: dict = config + self.cz = factory.commiter_factory(self.config) + + def __call__(self): + self.config + out.write("changelog") + changelog diff --git a/tests/test_changelog.py b/tests/test_changelog.py new file mode 100644 index 0000000000..1d8e129079 --- /dev/null +++ b/tests/test_changelog.py @@ -0,0 +1,199 @@ +import os + + +import pytest + +from commitizen import changelog + + +COMMIT_LOG = [ + "bump: version 1.5.0 → 1.5.1", + "", + "Merge pull request #29 from esciara/issue_28", + "fix: #28 allows poetry add on py36 envs", + "fix: #28 allows poetry add on py36 envs", + "", + "Merge pull request #26 from Woile/dependabot/pip/black-tw-19.3b0", + "chore(deps-dev): update black requirement from ^18.3-alpha.0 to ^19.3b0", + "Merge pull request #27 from Woile/dependabot/pip/mypy-tw-0.701", + "chore(deps-dev): update mypy requirement from ^0.700.0 to ^0.701", + "chore(deps-dev): update mypy requirement from ^0.700.0 to ^0.701", + "Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version.", + "- [Release notes](https://github.com/python/mypy/releases)", + "- [Commits](https://github.com/python/mypy/compare/v0.700...v0.701)", + "", + "Signed-off-by: dependabot[bot] ", + "chore(deps-dev): update black requirement from ^18.3-alpha.0 to ^19.3b0", + "Updates the requirements on [black](https://github.com/ambv/black) to permit the latest version.", + "- [Release notes](https://github.com/ambv/black/releases)", + "- [Commits](https://github.com/ambv/black/commits)", + "", + "Signed-off-by: dependabot[bot] ", + "bump: version 1.4.0 → 1.5.0", + "", + "docs: add info about extra pattern in the files when bumping", + "", + "feat(bump): it is now possible to specify a pattern in the files attr to replace the version", + "", +] + +CHANGELOG_TEMPLATE = """ +## 1.0.0 (2019-07-12) + +### Bug fixes + +- issue in poetry add preventing the installation in py36 +- **users**: lorem ipsum apap + + +### Features + +- it is possible to specify a pattern to be matched in configuration files bump. + +## 0.9 (2019-07-11) + +### Bug fixes + +- holis + +""" + + +@pytest.fixture +def existing_changelog_file(request): + changelog_path = "tests/CHANGELOG.md" + + with open(changelog_path, "w") as f: + f.write(CHANGELOG_TEMPLATE) + + yield changelog_path + + os.remove(changelog_path) + + +def test_read_changelog_blocks(existing_changelog_file): + blocks = changelog.find_version_blocks(existing_changelog_file) + blocks = list(blocks) + amount_of_blocks = len(blocks) + assert amount_of_blocks == 2 + + +VERSION_CASES: list = [ + ("## 1.0.0 (2019-07-12)", {"version": "1.0.0", "date": "2019-07-12"}), + ("## 2.3.0a0", {"version": "2.3.0a0", "date": None}), + ("## 0.10.0a0", {"version": "0.10.0a0", "date": None}), + ("## 1.0.0rc0", {"version": "1.0.0rc0", "date": None}), + ("## 1beta", {"version": "1beta", "date": None}), + ( + "## 1.0.0rc1+e20d7b57f3eb (2019-3-24)", + {"version": "1.0.0rc1+e20d7b57f3eb", "date": "2019-3-24"}, + ), + ("### Bug fixes", {}), + ("- issue in poetry add preventing the installation in py36", {}), +] + +CATEGORIES_CASES: list = [ + ("## 1.0.0 (2019-07-12)", {}), + ("## 2.3.0a0", {}), + ("### Bug fixes", {"category": "Bug fixes"}), + ("### Features", {"category": "Features"}), + ("- issue in poetry add preventing the installation in py36", {}), +] +CATEGORIES_TRANSFORMATIONS: list = [ + ("Bug fixes", "fix"), + ("Features", "feat"), + ("BREAKING CHANGES", "BREAKING CHANGES"), +] + +MESSAGES_CASES: list = [ + ("## 1.0.0 (2019-07-12)", {}), + ("## 2.3.0a0", {}), + ("### Bug fixes", {}), + ( + "- name no longer accept invalid chars", + {"message": "name no longer accept invalid chars", "scope": None}, + ), + ( + "- **users**: lorem ipsum apap", + {"message": "lorem ipsum apap", "scope": "users"}, + ), +] + + +@pytest.mark.parametrize("test_input,expected", VERSION_CASES) +def test_parse_md_version(test_input, expected): + assert changelog.parse_md_version(test_input) == expected + + +@pytest.mark.parametrize("test_input,expected", CATEGORIES_CASES) +def test_parse_md_category(test_input, expected): + assert changelog.parse_md_category(test_input) == expected + + +@pytest.mark.parametrize("test_input,expected", CATEGORIES_TRANSFORMATIONS) +def test_transform_category(test_input, expected): + assert changelog.transform_category(test_input) == expected + + +@pytest.mark.parametrize("test_input,expected", MESSAGES_CASES) +def test_parse_md_message(test_input, expected): + assert changelog.parse_md_message(test_input) == expected + + +def test_transform_category_fail(): + with pytest.raises(ValueError) as excinfo: + changelog.transform_category("Bugs") + assert "Could not match a category" in str(excinfo.value) + + +def test_generate_block_tree(existing_changelog_file): + blocks = changelog.find_version_blocks(existing_changelog_file) + block = next(blocks) + tree = changelog.generate_block_tree(block) + assert tree == { + "commits": [ + { + "scope": None, + "message": "issue in poetry add preventing the installation in py36", + "category": "fix", + }, + {"scope": "users", "message": "lorem ipsum apap", "category": "fix"}, + { + "scope": None, + "message": "it is possible to specify a pattern to be matched in configuration files bump.", + "category": "feat", + }, + ], + "version": "1.0.0", + "date": "2019-07-12", + } + + +def test_generate_full_tree(existing_changelog_file): + blocks = changelog.find_version_blocks(existing_changelog_file) + tree = list(changelog.generate_full_tree(blocks)) + + assert tree == [ + { + "commits": [ + { + "scope": None, + "message": "issue in poetry add preventing the installation in py36", + "category": "fix", + }, + {"scope": "users", "message": "lorem ipsum apap", "category": "fix"}, + { + "scope": None, + "message": "it is possible to specify a pattern to be matched in configuration files bump.", + "category": "feat", + }, + ], + "version": "1.0.0", + "date": "2019-07-12", + }, + { + "commits": [{"scope": None, "message": "holis", "category": "fix"}], + "version": "0.9", + "date": "2019-07-11", + }, + ] From 9326693fbc51bef6068632ea0b72fcf37b88083d Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Wed, 15 Jan 2020 19:42:22 +0800 Subject: [PATCH 045/427] feat(cz/base): add default process_commit for processing commit message --- commitizen/cz/base.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/commitizen/cz/base.py b/commitizen/cz/base.py index cd0775e6f7..d41b876c58 100644 --- a/commitizen/cz/base.py +++ b/commitizen/cz/base.py @@ -59,3 +59,10 @@ def schema_pattern(self) -> Optional[str]: def info(self) -> Optional[str]: """Information about the standardized commit message.""" raise NotImplementedError("Not Implemented yet") + + def process_commit(self, commit: str) -> str: + """Process commit for changelog. + + If not overwritten, it returns the first line of commit. + """ + return commit.split("\n")[0] From 0c3b666efe5c3b06ce4fe63110f37495e7412d64 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Wed, 15 Jan 2020 19:43:05 +0800 Subject: [PATCH 046/427] feat(cz/conventinal_commits): add changelog_map, changelog_pattern and implement process_commit --- .../cz/conventional_commits/conventional_commits.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index fcf0df4b58..c785977b0b 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -1,4 +1,6 @@ import os +import re +from collections import OrderedDict from typing import Any, Dict, List from commitizen import defaults @@ -29,6 +31,10 @@ def parse_subject(text): class ConventionalCommitsCz(BaseCommitizen): bump_pattern = defaults.bump_pattern bump_map = defaults.bump_map + changelog_pattern = r"^(BREAKING CHANGE|feat|fix)" + changelog_map = OrderedDict( + {"BREAKING CHANGES": "breaking", "feat": "feat", "fix": "fix"} + ) def questions(self) -> List[Dict[str, Any]]: questions: List[Dict[str, Any]] = [ @@ -183,3 +189,8 @@ def info(self) -> str: with open(filepath, "r") as f: content = f.read() return content + + def process_commit(self, commit: str) -> str: + pat = re.compile(self.schema_pattern()) + m = re.match(pat, commit) + return m.group(3).strip() From cda6be415e89dd12eb70b0945cd96b65e2fd89d0 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Wed, 15 Jan 2020 19:44:24 +0800 Subject: [PATCH 047/427] feat(commands/changelog): generate changelog_tree from all past commits TODO: find rev for each changelog entry --- commitizen/commands/changelog.py | 43 +++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index f859292125..9c5591254c 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -1,14 +1,45 @@ -from commitizen import factory, out, changelog +import re +from collections import OrderedDict + +from commitizen import factory, out, git +from commitizen.config import BaseConfig class Changelog: """Generate a changelog based on the commit history.""" - def __init__(self, config: dict, *args): - self.config: dict = config + def __init__(self, config: BaseConfig, *args): + self.config: BaseConfig = config self.cz = factory.commiter_factory(self.config) + # TODO: make these argument + self.skip_merge = True + def __call__(self): - self.config - out.write("changelog") - changelog + changelog_map = self.cz.changelog_map + changelog_pattern = self.cz.changelog_pattern + if not changelog_map: + out.error( + f"'{self.config.settings['name']}' rule does not support changelog" + ) + + pat = re.compile(changelog_pattern) + + changelog_tree = OrderedDict({value: [] for value in changelog_map.values()}) + commits = git.get_commits() + for commit in commits: + if self.skip_merge and commit.startswith("Merge"): + continue + + for message in commit.split("\n"): + result = pat.search(message) + if not result: + continue + found_keyword = result.group(0) + processed_commit = self.cz.process_commit(commit) + changelog_tree[changelog_map[found_keyword]].append(processed_commit) + break + + # TODO: handle rev + # an entry of changelog contains 'rev -> change_type -> message' + # the code above handles `change_type -> message` part From dee82859d00833dfbfc8b2319d5e33d8ad45afc1 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 17 Jan 2020 16:31:04 +0800 Subject: [PATCH 048/427] feat(changelog): generate changelog based on git log it will over write the existing file --- commitizen/commands/changelog.py | 40 +++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 9c5591254c..d9dfff89b7 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -12,8 +12,9 @@ def __init__(self, config: BaseConfig, *args): self.config: BaseConfig = config self.cz = factory.commiter_factory(self.config) - # TODO: make these argument + # TODO: make these attribute arguments self.skip_merge = True + self.file_name = "CHANGELOG.md" def __call__(self): changelog_map = self.cz.changelog_map @@ -25,21 +26,42 @@ def __call__(self): pat = re.compile(changelog_pattern) - changelog_tree = OrderedDict({value: [] for value in changelog_map.values()}) + changelog_entry_key = "Unreleased" + changelog_entry_values = OrderedDict({value: [] for value in changelog_map.values()}) commits = git.get_commits() + tag_map = {tag.rev: tag.name for tag in git.get_tags()} + + changelog_str = "# Changelog\n" for commit in commits: - if self.skip_merge and commit.startswith("Merge"): + if self.skip_merge and commit.message.startswith("Merge"): continue - for message in commit.split("\n"): + if commit.rev in tag_map: + changelog_str += f"\n## {changelog_entry_key}\n" + for key, values in changelog_entry_values.items(): + if not values: + continue + changelog_str += f"* {key}\n" + for value in values: + changelog_str += f" * {value}\n" + changelog_entry_key = tag_map[commit.rev] + + for message in commit.message.split("\n"): result = pat.search(message) if not result: continue found_keyword = result.group(0) - processed_commit = self.cz.process_commit(commit) - changelog_tree[changelog_map[found_keyword]].append(processed_commit) + processed_commit = self.cz.process_commit(commit.message) + changelog_entry_values[changelog_map[found_keyword]].append(processed_commit) break - # TODO: handle rev - # an entry of changelog contains 'rev -> change_type -> message' - # the code above handles `change_type -> message` part + changelog_str += f"\n## {changelog_entry_key}\n" + for key, values in changelog_entry_values.items(): + if not values: + continue + changelog_str += f"* {key}\n" + for value in values: + changelog_str += f" * {value}\n" + + with open(self.file_name, "w") as changelog_file: + changelog_file.write(changelog_str) From b5eb128fbd2f387a419654d547ed7ce0439d6653 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Wed, 15 Jan 2020 16:11:31 +0800 Subject: [PATCH 049/427] style(all): blackify --- commitizen/commands/__init__.py | 2 +- commitizen/commands/changelog.py | 8 ++++++-- tests/test_changelog.py | 29 +++++++++++++++++++++++------ 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/commitizen/commands/__init__.py b/commitizen/commands/__init__.py index 6d1d8a13e5..fde589f8df 100644 --- a/commitizen/commands/__init__.py +++ b/commitizen/commands/__init__.py @@ -15,7 +15,7 @@ "Bump", "Check", "Commit", - "Changelog" + "Changelog", "Example", "Info", "ListCz", diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index d9dfff89b7..54554c170c 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -27,7 +27,9 @@ def __call__(self): pat = re.compile(changelog_pattern) changelog_entry_key = "Unreleased" - changelog_entry_values = OrderedDict({value: [] for value in changelog_map.values()}) + changelog_entry_values = OrderedDict( + {value: [] for value in changelog_map.values()} + ) commits = git.get_commits() tag_map = {tag.rev: tag.name for tag in git.get_tags()} @@ -52,7 +54,9 @@ def __call__(self): continue found_keyword = result.group(0) processed_commit = self.cz.process_commit(commit.message) - changelog_entry_values[changelog_map[found_keyword]].append(processed_commit) + changelog_entry_values[changelog_map[found_keyword]].append( + processed_commit + ) break changelog_str += f"\n## {changelog_entry_key}\n" diff --git a/tests/test_changelog.py b/tests/test_changelog.py index 1d8e129079..ba0a730859 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -18,13 +18,19 @@ "Merge pull request #27 from Woile/dependabot/pip/mypy-tw-0.701", "chore(deps-dev): update mypy requirement from ^0.700.0 to ^0.701", "chore(deps-dev): update mypy requirement from ^0.700.0 to ^0.701", - "Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version.", + ( + "Updates the requirements on " + "[mypy](https://github.com/python/mypy) to permit the latest version." + ), "- [Release notes](https://github.com/python/mypy/releases)", "- [Commits](https://github.com/python/mypy/compare/v0.700...v0.701)", "", "Signed-off-by: dependabot[bot] ", "chore(deps-dev): update black requirement from ^18.3-alpha.0 to ^19.3b0", - "Updates the requirements on [black](https://github.com/ambv/black) to permit the latest version.", + ( + "Updates the requirements on [black](https://github.com/ambv/black)" + " to permit the latest version." + ), "- [Release notes](https://github.com/ambv/black/releases)", "- [Commits](https://github.com/ambv/black/commits)", "", @@ -33,7 +39,10 @@ "", "docs: add info about extra pattern in the files when bumping", "", - "feat(bump): it is now possible to specify a pattern in the files attr to replace the version", + ( + "feat(bump): it is now possible to specify a pattern " + "in the files attr to replace the version" + ), "", ] @@ -160,7 +169,10 @@ def test_generate_block_tree(existing_changelog_file): {"scope": "users", "message": "lorem ipsum apap", "category": "fix"}, { "scope": None, - "message": "it is possible to specify a pattern to be matched in configuration files bump.", + "message": ( + "it is possible to specify a pattern to be matched " + "in configuration files bump." + ), "category": "feat", }, ], @@ -178,13 +190,18 @@ def test_generate_full_tree(existing_changelog_file): "commits": [ { "scope": None, - "message": "issue in poetry add preventing the installation in py36", + "message": ( + "issue in poetry add preventing the installation in py36" + ), "category": "fix", }, {"scope": "users", "message": "lorem ipsum apap", "category": "fix"}, { "scope": None, - "message": "it is possible to specify a pattern to be matched in configuration files bump.", + "message": ( + "it is possible to specify a pattern to be matched " + "in configuration files bump." + ), "category": "feat", }, ], From 0878114a5d37a5c82793064088b185e9b12c8fb7 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 23 Jan 2020 15:57:18 +0800 Subject: [PATCH 050/427] refactor(commands/changelog): use jinja2 template instead of string concatenation to build changelog * install jinja2 * use named caputure group for changelog_pattern --- commitizen/commands/changelog.py | 78 +++++++++++-------- commitizen/cz/changelog_template.j2 | 13 ++++ .../conventional_commits.py | 6 +- pyproject.toml | 2 +- 4 files changed, 61 insertions(+), 38 deletions(-) create mode 100644 commitizen/cz/changelog_template.j2 diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 54554c170c..dc3c131529 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -1,71 +1,81 @@ import re from collections import OrderedDict -from commitizen import factory, out, git +from jinja2 import Template + +from commitizen import factory, out, git, cz from commitizen.config import BaseConfig +try: + import importlib.resources as pkg_resources +except ImportError: + # Try backported to PY<37 `importlib_resources`. + import importlib_resources as pkg_resources + class Changelog: """Generate a changelog based on the commit history.""" - def __init__(self, config: BaseConfig, *args): + def __init__(self, config: BaseConfig, args): self.config: BaseConfig = config self.cz = factory.commiter_factory(self.config) # TODO: make these attribute arguments - self.skip_merge = True - self.file_name = "CHANGELOG.md" + self.skip_merge = args["skip_merge"] + self.file_name = args["file_name"] + self.dry_run = args["dry_run"] def __call__(self): changelog_map = self.cz.changelog_map changelog_pattern = self.cz.changelog_pattern - if not changelog_map: + if not changelog_map or not changelog_pattern: out.error( f"'{self.config.settings['name']}' rule does not support changelog" ) pat = re.compile(changelog_pattern) - changelog_entry_key = "Unreleased" - changelog_entry_values = OrderedDict( - {value: [] for value in changelog_map.values()} - ) + entries = OrderedDict() + commits = git.get_commits() tag_map = {tag.rev: tag.name for tag in git.get_tags()} - changelog_str = "# Changelog\n" + # The latest commit is not tagged + latest_commit = commits[0] + if latest_commit.rev not in tag_map: + current_key = "Unreleased" + entries[current_key] = OrderedDict( + {value: [] for value in changelog_map.values()} + ) + else: + current_key = tag_map[latest_commit.rev] + for commit in commits: if self.skip_merge and commit.message.startswith("Merge"): continue if commit.rev in tag_map: - changelog_str += f"\n## {changelog_entry_key}\n" - for key, values in changelog_entry_values.items(): - if not values: - continue - changelog_str += f"* {key}\n" - for value in values: - changelog_str += f" * {value}\n" - changelog_entry_key = tag_map[commit.rev] - - for message in commit.message.split("\n"): - result = pat.search(message) - if not result: - continue - found_keyword = result.group(0) - processed_commit = self.cz.process_commit(commit.message) - changelog_entry_values[changelog_map[found_keyword]].append( - processed_commit + current_key = tag_map[commit.rev] + entries[current_key] = OrderedDict( + {value: [] for value in changelog_map.values()} ) - break - changelog_str += f"\n## {changelog_entry_key}\n" - for key, values in changelog_entry_values.items(): - if not values: + matches = pat.match(commit.message) + if not matches: continue - changelog_str += f"* {key}\n" - for value in values: - changelog_str += f" * {value}\n" + + processed_commit = self.cz.process_commit(commit.message) + for group_name, commit_type in changelog_map.items(): + if matches.group(group_name): + entries[current_key][commit_type].append(processed_commit) + break + + template_file = pkg_resources.read_text(cz, "changelog_template.j2") + jinja_template = Template(template_file) + changelog_str = jinja_template.render(entries=entries) + if self.dry_run: + out.write(changelog_str) + raise SystemExit(0) with open(self.file_name, "w") as changelog_file: changelog_file.write(changelog_str) diff --git a/commitizen/cz/changelog_template.j2 b/commitizen/cz/changelog_template.j2 new file mode 100644 index 0000000000..4d3516577e --- /dev/null +++ b/commitizen/cz/changelog_template.j2 @@ -0,0 +1,13 @@ +# CHANGELOG + +{% for entry_key, entry_value in entries.items()-%} +## {{entry_key}} +{% for type, commits in entry_value.items()-%} +{%-if commits-%} +### {{type}} +{% for commit in commits-%} +- {{commit}} +{%-endfor %} +{% endif %} +{%-endfor %} +{% endfor %} diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index c785977b0b..29c9d9a880 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -31,10 +31,10 @@ def parse_subject(text): class ConventionalCommitsCz(BaseCommitizen): bump_pattern = defaults.bump_pattern bump_map = defaults.bump_map - changelog_pattern = r"^(BREAKING CHANGE|feat|fix)" - changelog_map = OrderedDict( - {"BREAKING CHANGES": "breaking", "feat": "feat", "fix": "fix"} + changelog_pattern = ( + r"(?P.*\n\nBREAKING CHANGE)|(?P^feat)|(?P^fix)" ) + changelog_map = OrderedDict({"break": "breaking", "feat": "feat", "fix": "fix"}) def questions(self) -> List[Dict[str, Any]]: questions: List[Dict[str, Any]] = [ diff --git a/pyproject.toml b/pyproject.toml index 38f69fca9a..97add2bf9c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,7 +51,7 @@ colorama = "^0.4.1" termcolor = "^1.1" packaging = ">=19,<21" tomlkit = "^0.5.3" -jinja2 = {version = "^2.10.3", optional = true} +jinja2 = "^2.10.3" [tool.poetry.dev-dependencies] ipython = "^7.2" From 4982faede0a4603c8a427dc5d111ee4a16320323 Mon Sep 17 00:00:00 2001 From: LeeW Date: Thu, 23 Jan 2020 21:35:38 +0800 Subject: [PATCH 051/427] fix(cli): add changelog arguments --- commitizen/cli.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index 352e83f93f..d6b876c710 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -40,8 +40,27 @@ }, { "name": ["changelog", "ch"], - "help": "create new changelog", + "help": "generate changelog (note that it will overwrite existing file)", "func": commands.Changelog, + "arguments": [ + { + "name": "--dry-run", + "action": "store_true", + "default": False, + "help": "show changelog to stdout", + }, + { + "name": "--skip-merge", + "action": "store_true", + "default": False, + "help": "whether to skip merge commit", + }, + { + "name": "--file-name", + "default": "CHANGELOG.md", + "help": "file name of changelog", + }, + ], }, { "name": ["commit", "c"], From 2cfd9defe8f168dce373526c225b631e06523009 Mon Sep 17 00:00:00 2001 From: LeeW Date: Thu, 23 Jan 2020 21:36:27 +0800 Subject: [PATCH 052/427] feat(commands/changlog): add --start-rev argument to `cz changelog` --- commitizen/cli.py | 8 ++++++++ commitizen/commands/changelog.py | 7 +++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index d6b876c710..ce6106863a 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -60,6 +60,14 @@ "default": "CHANGELOG.md", "help": "file name of changelog", }, + { + "name": "--start-rev", + "default": None, + "help": ( + "start rev of the changelog." + "If not set, it will generate changelog from the start" + ), + }, ], }, { diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index dc3c131529..0f75138f07 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -20,10 +20,10 @@ def __init__(self, config: BaseConfig, args): self.config: BaseConfig = config self.cz = factory.commiter_factory(self.config) - # TODO: make these attribute arguments self.skip_merge = args["skip_merge"] self.file_name = args["file_name"] self.dry_run = args["dry_run"] + self.start_rev = args["start_rev"] def __call__(self): changelog_map = self.cz.changelog_map @@ -37,7 +37,10 @@ def __call__(self): entries = OrderedDict() - commits = git.get_commits() + if self.start_rev: + commits = git.get_commits(start=self.start_rev) + else: + commits = git.get_commits() tag_map = {tag.rev: tag.name for tag in git.get_tags()} # The latest commit is not tagged From 3df0a7ac831b7b4a8443e69264763899fcf2b3b2 Mon Sep 17 00:00:00 2001 From: LeeW Date: Thu, 23 Jan 2020 21:48:52 +0800 Subject: [PATCH 053/427] style(cli): fix flake8 issue --- commitizen/cli.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index ce6106863a..302ca7fb2a 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -40,7 +40,9 @@ }, { "name": ["changelog", "ch"], - "help": "generate changelog (note that it will overwrite existing file)", + "help": ( + "generate changelog (note that it will overwrite existing file)" + ), "func": commands.Changelog, "arguments": [ { From ace33cc14736123dad1f8329779610b569f32634 Mon Sep 17 00:00:00 2001 From: LeeW Date: Thu, 23 Jan 2020 21:53:17 +0800 Subject: [PATCH 054/427] refactor(commands/changelog): remove redundant if statement --- commitizen/commands/changelog.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 0f75138f07..7d66d1e3c0 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -35,14 +35,10 @@ def __call__(self): pat = re.compile(changelog_pattern) - entries = OrderedDict() - - if self.start_rev: - commits = git.get_commits(start=self.start_rev) - else: - commits = git.get_commits() + commits = git.get_commits(start=self.start_rev) tag_map = {tag.rev: tag.name for tag in git.get_tags()} + entries = OrderedDict() # The latest commit is not tagged latest_commit = commits[0] if latest_commit.rev not in tag_map: From a9285253874e40987be06e05f1fa06ad2cc78c9e Mon Sep 17 00:00:00 2001 From: LeeW Date: Thu, 23 Jan 2020 22:18:28 +0800 Subject: [PATCH 055/427] refactor(tests/utils): move create_file_and_commit to tests/utils --- tests/commands/test_bump_command.py | 13 +------------ tests/utils.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 12 deletions(-) create mode 100644 tests/utils.py diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index e5ef886f63..3907d19527 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -1,20 +1,9 @@ import sys -import uuid -from pathlib import Path -from typing import Optional import pytest from commitizen import cli, cmd, git - - -def create_file_and_commit(message: str, filename: Optional[str] = None): - if not filename: - filename = str(uuid.uuid4()) - - Path(f"./{filename}").touch() - cmd.run("git add .") - git.commit(message) +from tests.utils import create_file_and_commit @pytest.mark.usefixtures("tmp_commitizen_project") diff --git a/tests/utils.py b/tests/utils.py new file mode 100644 index 0000000000..64598b8df1 --- /dev/null +++ b/tests/utils.py @@ -0,0 +1,14 @@ +import uuid +from pathlib import Path +from typing import Optional + +from commitizen import cmd, git + + +def create_file_and_commit(message: str, filename: Optional[str] = None): + if not filename: + filename = str(uuid.uuid4()) + + Path(f"./{filename}").touch() + cmd.run("git add .") + git.commit(message) From 5f9cf46a0b284c41a5baaa61e49c33be21d785e3 Mon Sep 17 00:00:00 2001 From: LeeW Date: Thu, 23 Jan 2020 22:24:45 +0800 Subject: [PATCH 056/427] feat(commands/changelog): exit when there is no commit exists --- commitizen/commands/changelog.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 7d66d1e3c0..9fc97e7285 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -5,6 +5,7 @@ from commitizen import factory, out, git, cz from commitizen.config import BaseConfig +from commitizen.error_codes import NO_COMMITS_FOUND try: import importlib.resources as pkg_resources @@ -36,6 +37,9 @@ def __call__(self): pat = re.compile(changelog_pattern) commits = git.get_commits(start=self.start_rev) + if not commits: + raise SystemExit(NO_COMMITS_FOUND) + tag_map = {tag.rev: tag.name for tag in git.get_tags()} entries = OrderedDict() From 3a80c56ac831de5e6b58fb4544d5ae03bdcdf04e Mon Sep 17 00:00:00 2001 From: LeeW Date: Thu, 23 Jan 2020 22:42:25 +0800 Subject: [PATCH 057/427] fix(commands/changelog): remove --skip-merge argument by default, unrelated commits are ignored --- commitizen/cli.py | 6 ------ commitizen/commands/changelog.py | 4 ---- commitizen/cz/changelog_template.j2 | 12 ++++++------ 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index 302ca7fb2a..197fd177e3 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -51,12 +51,6 @@ "default": False, "help": "show changelog to stdout", }, - { - "name": "--skip-merge", - "action": "store_true", - "default": False, - "help": "whether to skip merge commit", - }, { "name": "--file-name", "default": "CHANGELOG.md", diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 9fc97e7285..5dd54663c3 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -21,7 +21,6 @@ def __init__(self, config: BaseConfig, args): self.config: BaseConfig = config self.cz = factory.commiter_factory(self.config) - self.skip_merge = args["skip_merge"] self.file_name = args["file_name"] self.dry_run = args["dry_run"] self.start_rev = args["start_rev"] @@ -54,9 +53,6 @@ def __call__(self): current_key = tag_map[latest_commit.rev] for commit in commits: - if self.skip_merge and commit.message.startswith("Merge"): - continue - if commit.rev in tag_map: current_key = tag_map[commit.rev] entries[current_key] = OrderedDict( diff --git a/commitizen/cz/changelog_template.j2 b/commitizen/cz/changelog_template.j2 index 4d3516577e..eb4a096cc4 100644 --- a/commitizen/cz/changelog_template.j2 +++ b/commitizen/cz/changelog_template.j2 @@ -1,13 +1,13 @@ # CHANGELOG -{% for entry_key, entry_value in entries.items()-%} +{% for entry_key, entry_value in entries.items() -%} ## {{entry_key}} -{% for type, commits in entry_value.items()-%} -{%-if commits-%} +{% for type, commits in entry_value.items() -%} +{%- if commits -%} ### {{type}} {% for commit in commits-%} - {{commit}} -{%-endfor %} +{%- endfor %} {% endif %} -{%-endfor %} -{% endfor %} +{%- endfor %} +{%- endfor %} From 2a2a29e6121cdeb52bdfeecf67852cb617e7d8e3 Mon Sep 17 00:00:00 2001 From: LeeW Date: Thu, 23 Jan 2020 22:47:13 +0800 Subject: [PATCH 058/427] fix(commitizen/cz): set changelog_map, changelog_pattern to none as default without this default, getting these attributes will be an error --- commitizen/commands/changelog.py | 4 +++- commitizen/cz/base.py | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 5dd54663c3..56f93a922d 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -5,7 +5,7 @@ from commitizen import factory, out, git, cz from commitizen.config import BaseConfig -from commitizen.error_codes import NO_COMMITS_FOUND +from commitizen.error_codes import NO_COMMITS_FOUND, NO_PATTERN_MAP try: import importlib.resources as pkg_resources @@ -32,11 +32,13 @@ def __call__(self): out.error( f"'{self.config.settings['name']}' rule does not support changelog" ) + raise SystemExit(NO_PATTERN_MAP) pat = re.compile(changelog_pattern) commits = git.get_commits(start=self.start_rev) if not commits: + out.error("No commits found") raise SystemExit(NO_COMMITS_FOUND) tag_map = {tag.rev: tag.name for tag in git.get_tags()} diff --git a/commitizen/cz/base.py b/commitizen/cz/base.py index d41b876c58..ff6147d29f 100644 --- a/commitizen/cz/base.py +++ b/commitizen/cz/base.py @@ -9,6 +9,8 @@ class BaseCommitizen(metaclass=ABCMeta): bump_pattern: Optional[str] = None bump_map: Optional[dict] = None + changelog_pattern: Optional[str] = None + changelog_map: Optional[dict] = None default_style_config: List[Tuple[str, str]] = [ ("qmark", "fg:#ff9d00 bold"), ("question", "bold"), From 0b0676d11ed7036c44d97972d669ad60b8136678 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 23 Jan 2020 23:17:15 +0800 Subject: [PATCH 059/427] fix(changelog_template): fix list format --- commitizen/cz/changelog_template.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commitizen/cz/changelog_template.j2 b/commitizen/cz/changelog_template.j2 index eb4a096cc4..d3fba14668 100644 --- a/commitizen/cz/changelog_template.j2 +++ b/commitizen/cz/changelog_template.j2 @@ -7,7 +7,7 @@ ### {{type}} {% for commit in commits-%} - {{commit}} -{%- endfor %} +{% endfor %} {% endif %} {%- endfor %} {%- endfor %} From 2b15a1bfdab50888ec07a530bf04ca9b13387ad0 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 23 Jan 2020 23:17:47 +0800 Subject: [PATCH 060/427] test(commands/changelog): add test case for changelog command --- tests/commands/test_changelog_command.py | 65 ++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 tests/commands/test_changelog_command.py diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py new file mode 100644 index 0000000000..d6bf680553 --- /dev/null +++ b/tests/commands/test_changelog_command.py @@ -0,0 +1,65 @@ +import sys + +import pytest + +from commitizen import cli +from tests.utils import create_file_and_commit + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_changlog_on_empty_project(mocker): + testargs = ["cz", "changelog", "--dry-run"] + mocker.patch.object(sys, "argv", testargs) + + with pytest.raises(SystemExit): + cli.main() + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_changlog_from_start(mocker, capsys): + create_file_and_commit("feat: new file") + create_file_and_commit("refactor: not in changelog") + create_file_and_commit("Merge into master") + + testargs = ["cz", "changelog", "--dry-run"] + mocker.patch.object(sys, "argv", testargs) + + with pytest.raises(SystemExit): + cli.main() + + out, _ = capsys.readouterr() + assert out == "# CHANGELOG\n\n## Unreleased\n### feat\n- new file\n\n\n" + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_changlog_from_version_zero_point_two(mocker, capsys): + create_file_and_commit("feat: new file") + create_file_and_commit("refactor: not in changelog") + + # create tag + testargs = ["cz", "bump", "--yes"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + capsys.readouterr() + + create_file_and_commit("feat: after 0.2.0") + create_file_and_commit("feat: after 0.2") + + testargs = ["cz", "changelog", "--start-rev", "0.2.0", "--dry-run"] + mocker.patch.object(sys, "argv", testargs) + with pytest.raises(SystemExit): + cli.main() + + out, _ = capsys.readouterr() + assert out == "# CHANGELOG\n\n## Unreleased\n### feat\n- after 0.2\n- after 0.2.0\n\n\n" + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_changlog_with_unsupported_cz(mocker, capsys): + testargs = ["cz", "-n", "cz_jira", "changelog", "--dry-run"] + mocker.patch.object(sys, "argv", testargs) + + with pytest.raises(SystemExit): + cli.main() + out, err = capsys.readouterr() + assert "'cz_jira' rule does not support changelog" in err From a032fa4926e2e437b3096d604fe2008e59a25ec0 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Thu, 23 Jan 2020 23:40:20 +0800 Subject: [PATCH 061/427] refactor(templates): move changelog_template from cz to templates --- commitizen/commands/changelog.py | 13 +++++-------- commitizen/templates/__init__.py | 0 commitizen/{cz => templates}/changelog_template.j2 | 0 3 files changed, 5 insertions(+), 8 deletions(-) create mode 100644 commitizen/templates/__init__.py rename commitizen/{cz => templates}/changelog_template.j2 (100%) diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 56f93a922d..8ea3c5cda5 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -1,18 +1,13 @@ import re +import pkg_resources from collections import OrderedDict from jinja2 import Template -from commitizen import factory, out, git, cz +from commitizen import factory, out, git from commitizen.config import BaseConfig from commitizen.error_codes import NO_COMMITS_FOUND, NO_PATTERN_MAP -try: - import importlib.resources as pkg_resources -except ImportError: - # Try backported to PY<37 `importlib_resources`. - import importlib_resources as pkg_resources - class Changelog: """Generate a changelog based on the commit history.""" @@ -71,7 +66,9 @@ def __call__(self): entries[current_key][commit_type].append(processed_commit) break - template_file = pkg_resources.read_text(cz, "changelog_template.j2") + template_file = pkg_resources.resource_string( + __name__, "../templates/changelog_template.j2" + ).decode("utf-8") jinja_template = Template(template_file) changelog_str = jinja_template.render(entries=entries) if self.dry_run: diff --git a/commitizen/templates/__init__.py b/commitizen/templates/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/commitizen/cz/changelog_template.j2 b/commitizen/templates/changelog_template.j2 similarity index 100% rename from commitizen/cz/changelog_template.j2 rename to commitizen/templates/changelog_template.j2 From 384018d0bf386947bd82f2f8d9d7f3ae65517ac4 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 24 Jan 2020 08:08:12 +0800 Subject: [PATCH 062/427] refactor(cli): reorder commands --- commitizen/cli.py | 100 +++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index 197fd177e3..b0cb76f8fd 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -34,37 +34,9 @@ # "required": True, "commands": [ { - "name": "ls", - "help": "show available commitizens", - "func": commands.ListCz, - }, - { - "name": ["changelog", "ch"], - "help": ( - "generate changelog (note that it will overwrite existing file)" - ), - "func": commands.Changelog, - "arguments": [ - { - "name": "--dry-run", - "action": "store_true", - "default": False, - "help": "show changelog to stdout", - }, - { - "name": "--file-name", - "default": "CHANGELOG.md", - "help": "file name of changelog", - }, - { - "name": "--start-rev", - "default": None, - "help": ( - "start rev of the changelog." - "If not set, it will generate changelog from the start" - ), - }, - ], + "name": ["init"], + "help": "init commitizen configuration", + "func": commands.Init, }, { "name": ["commit", "c"], @@ -83,6 +55,11 @@ }, ], }, + { + "name": "ls", + "help": "show available commitizens", + "func": commands.ListCz, + }, { "name": "example", "help": "show commit example", @@ -142,33 +119,30 @@ ], }, { - "name": ["version"], + "name": ["changelog", "ch"], "help": ( - "get the version of the installed commitizen or the current project" - " (default: installed commitizen)" + "generate changelog (note that it will overwrite existing file)" ), - "func": commands.Version, + "func": commands.Changelog, "arguments": [ { - "name": ["-p", "--project"], - "help": "get the version of the current project", + "name": "--dry-run", "action": "store_true", - "exclusive_group": "group1", + "default": False, + "help": "show changelog to stdout", }, { - "name": ["-c", "--commitizen"], - "help": "get the version of the installed commitizen", - "action": "store_true", - "exclusive_group": "group1", + "name": "--file-name", + "default": "CHANGELOG.md", + "help": "file name of changelog", }, { - "name": ["-v", "--verbose"], + "name": "--start-rev", + "default": None, "help": ( - "get the version of both the installed commitizen " - "and the current project" + "start rev of the changelog." + "If not set, it will generate changelog from the start" ), - "action": "store_true", - "exclusive_group": "group1", }, ], }, @@ -194,9 +168,35 @@ ], }, { - "name": ["init"], - "help": "init commitizen configuration", - "func": commands.Init, + "name": ["version"], + "help": ( + "get the version of the installed commitizen or the current project" + " (default: installed commitizen)" + ), + "func": commands.Version, + "arguments": [ + { + "name": ["-p", "--project"], + "help": "get the version of the current project", + "action": "store_true", + "exclusive_group": "group1", + }, + { + "name": ["-c", "--commitizen"], + "help": "get the version of the installed commitizen", + "action": "store_true", + "exclusive_group": "group1", + }, + { + "name": ["-v", "--verbose"], + "help": ( + "get the version of both the installed commitizen " + "and the current project" + ), + "action": "store_true", + "exclusive_group": "group1", + }, + ], }, ], }, From 5ae9058fd5762297e40cb84711923f1f0fb98f5a Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 24 Jan 2020 11:37:16 +0800 Subject: [PATCH 063/427] docs(README): add changelog command --- docs/README.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/docs/README.md b/docs/README.md index c3f94ccf64..f05e03929b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -77,29 +77,34 @@ cz c ```bash $ cz --help usage: cz [-h] [--debug] [-n NAME] [--version] - {ls,commit,c,example,info,schema,bump} ... + {init,commit,c,ls,example,info,schema,bump,changelog,ch,check,version} + ... Commitizen is a cli tool to generate conventional commits. For more information about the topic go to https://conventionalcommits.org/ optional arguments: --h, --help show this help message and exit ---debug use debug mode --n NAME, --name NAME use the given commitizen ---version get the version of the installed commitizen + -h, --help show this help message and exit + --debug use debug mode + -n NAME, --name NAME use the given commitizen (default: + cz_conventional_commits) + --version get the version of the installed commitizen commands: -{ls,commit,c,example,info,schema,bump} - ls show available commitizens + {init,commit,c,ls,example,info,schema,bump,changelog,ch,check,version} + init init commitizen configuration commit (c) create new commit + ls show available commitizens example show commit example info show information about the cz schema show commit schema bump bump semantic version based on the git log + changelog (ch) generate changelog (note that it will overwrite + existing file) + check validates that a commit message matches the commitizen + schema version get the version of the installed commitizen or the current project (default: installed commitizen) - check validates that a commit message matches the commitizen schema - init init commitizen configuration ``` ## FAQ From 1ece991a2f6f8dc85d3c1364853854300a5bb825 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 24 Jan 2020 11:38:22 +0800 Subject: [PATCH 064/427] refactor(templates): remove unneeded __init__ file --- commitizen/templates/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 commitizen/templates/__init__.py diff --git a/commitizen/templates/__init__.py b/commitizen/templates/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 From 5b9c564a25e8c14c495478a14e5956497da3998f Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 24 Jan 2020 11:38:46 +0800 Subject: [PATCH 065/427] style(tests/commands/changelog): blackify --- tests/commands/test_changelog_command.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index d6bf680553..a053e6c238 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -51,7 +51,10 @@ def test_changlog_from_version_zero_point_two(mocker, capsys): cli.main() out, _ = capsys.readouterr() - assert out == "# CHANGELOG\n\n## Unreleased\n### feat\n- after 0.2\n- after 0.2.0\n\n\n" + assert ( + out + == "# CHANGELOG\n\n## Unreleased\n### feat\n- after 0.2\n- after 0.2.0\n\n\n" + ) @pytest.mark.usefixtures("tmp_commitizen_project") From 11e24d32e22a9ccc82d8a6b17b9b81add441c8f0 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 24 Jan 2020 11:39:54 +0800 Subject: [PATCH 066/427] refactor(templates): rename as "keep_a_changelog_template.j2" --- commitizen/commands/changelog.py | 2 +- .../{changelog_template.j2 => keep_a_changelog_template.j2} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename commitizen/templates/{changelog_template.j2 => keep_a_changelog_template.j2} (100%) diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 8ea3c5cda5..24926192c8 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -67,7 +67,7 @@ def __call__(self): break template_file = pkg_resources.resource_string( - __name__, "../templates/changelog_template.j2" + __name__, "../templates/keep_a_changelog_template.j2" ).decode("utf-8") jinja_template = Template(template_file) changelog_str = jinja_template.render(entries=entries) diff --git a/commitizen/templates/changelog_template.j2 b/commitizen/templates/keep_a_changelog_template.j2 similarity index 100% rename from commitizen/templates/changelog_template.j2 rename to commitizen/templates/keep_a_changelog_template.j2 From 2becf57dbe2ef079b053b721dc96ef48a06d0759 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 24 Jan 2020 16:36:17 +0800 Subject: [PATCH 067/427] feat(commands/changelog): make changelog_file an option in config --- commitizen/cli.py | 3 +-- commitizen/commands/changelog.py | 2 +- commitizen/defaults.py | 1 + tests/test_conf.py | 3 +++ 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index b0cb76f8fd..9d5130dce9 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -133,8 +133,7 @@ }, { "name": "--file-name", - "default": "CHANGELOG.md", - "help": "file name of changelog", + "help": "file name of changelog (default: 'CHANGELOG.md')", }, { "name": "--start-rev", diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 24926192c8..280f1b8f8c 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -16,7 +16,7 @@ def __init__(self, config: BaseConfig, args): self.config: BaseConfig = config self.cz = factory.commiter_factory(self.config) - self.file_name = args["file_name"] + self.file_name = args["file_name"] or self.config.settings.get("changelog_file") self.dry_run = args["dry_run"] self.start_rev = args["start_rev"] diff --git a/commitizen/defaults.py b/commitizen/defaults.py index 477a48e4a1..a694a11840 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -13,6 +13,7 @@ "version_files": [], "tag_format": None, # example v$version "bump_message": None, # bumped v$current_version to $new_version + "changelog_file": "CHANGELOG.md", } MAJOR = "MAJOR" diff --git a/tests/test_conf.py b/tests/test_conf.py index 58580e52a6..00dc4d40ad 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -44,6 +44,7 @@ "bump_message": None, "version_files": ["commitizen/__version__.py", "pyproject.toml"], "style": [["pointer", "reverse"], ["question", "underline"]], + "changelog_file": "CHANGELOG.md", } _new_settings = { @@ -53,6 +54,7 @@ "bump_message": None, "version_files": ["commitizen/__version__.py", "pyproject.toml"], "style": [["pointer", "reverse"], ["question", "underline"]], + "changelog_file": "CHANGELOG.md", } _read_settings = { @@ -60,6 +62,7 @@ "version": "1.0.0", "version_files": ["commitizen/__version__.py", "pyproject.toml"], "style": [["pointer", "reverse"], ["question", "underline"]], + "changelog_file": "CHANGELOG.md", } From 81b27c575e778da72731d8dbe6d219c0772c378c Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 24 Jan 2020 16:38:08 +0800 Subject: [PATCH 068/427] docs(config): add changlog_file a config option --- docs/config.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/config.md b/docs/config.md index d34c228ff9..67ce1f9a4f 100644 --- a/docs/config.md +++ b/docs/config.md @@ -67,8 +67,9 @@ The extra tab before the square brackets (`]`) at the end is required. | -------- | ---- | ------- | ----------- | | `name` | `str` | `"cz_conventional_commits"` | Name of the committing rules to use | | `version` | `str` | `None` | Current version. Example: "0.1.2" | -| `version_files` | `list` | `[ ]` | Files were the version will be updated. A pattern to match a line, can also be specified, separated by `:` [See more](https://commitizen-tools.github.io/commitizen/bump#files) | -| `tag_format` | `str` | `None` | Format for the git tag, useful for old projects, that use a convention like `"v1.2.1"`. [See more](https://commitizen-tools.github.io/commitizen/bump#tag_format) | -| `bump_message` | `str` | `None` | Create custom commit message, useful to skip ci. [See more](https://commitizen-tools.github.io/commitizen/bump#bump_message) | +| `version_files` | `list` | `[ ]` | Files were the version will be updated. A pattern to match a line, can also be specified, separated by `:` [See more](https://woile.github.io/commitizen/bump#files) | +| `tag_format` | `str` | `None` | Format for the git tag, useful for old projects, that use a convention like `"v1.2.1"`. [See more](https://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) | +| `changelog_file` | `str` | `CHANGELOG.md` | filename of exported changelog | | `style` | `list` | see above | Style for the prompts (It will merge this value with default style.) [See More (Styling your prompts with your favorite colors)](https://github.com/tmbo/questionary#additional-features) | | `customize` | `dict` | `None` | **This is only supported when config through `toml`.** Custom rules for committing and bumping. [See more](https://commitizen-tools.github.io/commitizen/customization/) | From 78b321e9999972e8aacce9fbf4f7f587d06f7b01 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Mon, 16 Mar 2020 22:25:18 +0800 Subject: [PATCH 069/427] fix(cz/conventional_commits): fix schema_pattern break due to rebase --- commitizen/cz/conventional_commits/conventional_commits.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index 29c9d9a880..8026532779 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -179,7 +179,7 @@ def schema(self) -> str: def schema_pattern(self) -> str: PATTERN = ( r"(build|ci|docs|feat|fix|perf|refactor|style|test|chore|revert|bump)" - r"(\(\S+\))?:\s.*" + r"(\(\S+\))?:(\s.*)" ) return PATTERN From 5bf5542e78ea575eebf258f3ac3cc9eb3a15a03f Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Mon, 16 Mar 2020 22:25:44 +0800 Subject: [PATCH 070/427] style: reformat --- commitizen/changelog.py | 2 +- commitizen/commands/__init__.py | 4 +--- commitizen/commands/changelog.py | 4 ++-- tests/test_changelog.py | 2 -- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/commitizen/changelog.py b/commitizen/changelog.py index 495a4513c4..b902640897 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -18,8 +18,8 @@ Options: - Generate full or partial changelog """ -from typing import Generator, List, Dict, Iterable import re +from typing import Dict, Generator, Iterable, List MD_VERSION_RE = r"^##\s(?P[a-zA-Z0-9.+]+)\s?\(?(?P[0-9-]+)?\)?" MD_CATEGORY_RE = r"^###\s(?P[a-zA-Z0-9.+\s]+)" diff --git a/commitizen/commands/__init__.py b/commitizen/commands/__init__.py index fde589f8df..806e384522 100644 --- a/commitizen/commands/__init__.py +++ b/commitizen/commands/__init__.py @@ -1,4 +1,5 @@ from .bump import Bump +from .changelog import Changelog from .check import Check from .commit import Commit from .example import Example @@ -7,9 +8,6 @@ from .list_cz import ListCz from .schema import Schema from .version import Version -from .init import Init -from .changelog import Changelog - __all__ = ( "Bump", diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 280f1b8f8c..b9bd966d27 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -1,10 +1,10 @@ import re -import pkg_resources from collections import OrderedDict +import pkg_resources from jinja2 import Template -from commitizen import factory, out, git +from commitizen import factory, git, out from commitizen.config import BaseConfig from commitizen.error_codes import NO_COMMITS_FOUND, NO_PATTERN_MAP diff --git a/tests/test_changelog.py b/tests/test_changelog.py index ba0a730859..dd34b9be92 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -1,11 +1,9 @@ import os - import pytest from commitizen import changelog - COMMIT_LOG = [ "bump: version 1.5.0 → 1.5.1", "", From 75d3938a4842b2aa667dcd902e376a5a01a797e5 Mon Sep 17 00:00:00 2001 From: Georgiy Ignatov Date: Wed, 22 Apr 2020 13:28:21 +0300 Subject: [PATCH 071/427] fix(git): fix returned value for GitCommit.message when body is empty GitCommit.message should return only title without excess newlines if commit body is empty. --- commitizen/git.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/commitizen/git.py b/commitizen/git.py index 058ba89a00..b8afa816dd 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -21,7 +21,10 @@ def __init__(self, rev, title, body=""): @property def message(self): - return f"{self.title}\n\n{self.body}" + message = self.title + if self.body: + message = message + f"\n\n{self.body}" + return message def __repr__(self): return f"{self.title} ({self.rev})" From bde1c4315a6a1ff2b565c94255fa20a4066dd5f4 Mon Sep 17 00:00:00 2001 From: Georgiy Ignatov Date: Wed, 22 Apr 2020 13:33:37 +0300 Subject: [PATCH 072/427] test(git): add test that checks GitCommit.message with empty body --- tests/test_git.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_git.py b/tests/test_git.py index ef7cb2cdc9..3a6638b329 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -47,3 +47,10 @@ def test_get_tag_names(mocker): "commitizen.cmd.run", return_value=FakeCommand(out="", err="No tag available") ) assert git.get_tag_names() == [] + + +def test_git_message_with_empty_body(): + commit_title = "Some Title" + commit = git.GitCommit("test_rev", "Some Title", body="") + + assert commit.message == commit_title From f21693efb5809138d4b027d3d1bde0800899976c Mon Sep 17 00:00:00 2001 From: Georgiy Ignatov Date: Wed, 22 Apr 2020 14:12:57 +0300 Subject: [PATCH 073/427] refactor(git): replace GitCommit.message code with one-liner --- commitizen/git.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/commitizen/git.py b/commitizen/git.py index b8afa816dd..a2531a87e4 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -21,10 +21,7 @@ def __init__(self, rev, title, body=""): @property def message(self): - message = self.title - if self.body: - message = message + f"\n\n{self.body}" - return message + return f"{self.title}\n\n{self.body}".strip() def __repr__(self): return f"{self.title} ({self.rev})" From 039f5e973c09aaea19e6b9da882bc36b880c56c2 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 22 Apr 2020 11:28:09 +0000 Subject: [PATCH 074/427] =?UTF-8?q?bump:=20version=201.18.1=20=E2=86=92=20?= =?UTF-8?q?1.18.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 4a7bff5447..4bd6f7be97 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.18.1" +__version__ = "1.18.2" diff --git a/pyproject.toml b/pyproject.toml index 38f69fca9a..6f2db9bab1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.18.1" +version = "1.18.2" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.18.1" +version = "1.18.2" description = "Python commitizen client tool" authors = ["Santiago Fraire "] license = "MIT" From c146901a64cafe38cb2cedd8b0d034dbf1aa15fa Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Wed, 22 Apr 2020 22:57:02 +0800 Subject: [PATCH 075/427] refactor(commands/init): fix typo --- commitizen/commands/init.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commitizen/commands/init.py b/commitizen/commands/init.py index b428d696cd..eef107d1d2 100644 --- a/commitizen/commands/init.py +++ b/commitizen/commands/init.py @@ -39,7 +39,7 @@ def __call__(self): def _ask_config_path(self) -> str: name = questionary.select( - "Please choose a supported config file: (default: pyproject.tml)", + "Please choose a supported config file: (default: pyproject.toml)", choices=long_term_support_config_files, default="pyproject.toml", style=self.cz.style, @@ -48,7 +48,7 @@ def _ask_config_path(self) -> str: def _ask_name(self) -> str: name = questionary.select( - "Please choose a cz: (default: cz_conventional_commits)", + "Please choose a cz (commit rule): (default: cz_conventional_commits)", choices=list(registry.keys()), default="cz_conventional_commits", style=self.cz.style, From 368a0b40071e17bdf97343fdd34764f47513ae9b Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 22 Apr 2020 15:02:28 +0000 Subject: [PATCH 076/427] =?UTF-8?q?bump:=20version=201.18.2=20=E2=86=92=20?= =?UTF-8?q?1.18.3?= 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 4bd6f7be97..14e8848aa1 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.18.2" +__version__ = "1.18.3" diff --git a/pyproject.toml b/pyproject.toml index 6f2db9bab1..689805eacd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.18.2" +version = "1.18.3" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.18.2" +version = "1.18.3" description = "Python commitizen client tool" authors = ["Santiago Fraire "] license = "MIT" From e71061a2e4a46456d2d67c47072bb58d0942f1eb Mon Sep 17 00:00:00 2001 From: Michael Kuc Date: Fri, 24 Apr 2020 09:49:45 +0100 Subject: [PATCH 077/427] docs(third-party): add third-party template documentation Add a new docs section for third-party contributed commit templates. This way new templates do not need to be merged into the main codebase, and instead exist as satellite repositories. See #158 for motivation. --- docs/README.md | 4 ++++ docs/third-party-commitizen.md | 12 ++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 docs/third-party-commitizen.md diff --git a/docs/README.md b/docs/README.md index c3f94ccf64..cdeef31a76 100644 --- a/docs/README.md +++ b/docs/README.md @@ -102,6 +102,10 @@ commands: init init commitizen configuration ``` +## Third-Party Commitizen Templates + +See [docs/third-party-commitizen.md](third-party-commitizen.md). + ## FAQ ### Why are `revert` and `chore` valid types in the check pattern of cz conventional_commits but not types we can select? diff --git a/docs/third-party-commitizen.md b/docs/third-party-commitizen.md new file mode 100644 index 0000000000..0b09f015cf --- /dev/null +++ b/docs/third-party-commitizen.md @@ -0,0 +1,12 @@ +## Third-Party Commitizen Templates + +In addition to the native templates, some alternative commit format templates +are available as PyPI packages (installable with `pip`). + +### [Conventional JIRA](https://pypi.org/project/conventional-JIRA/) + +Just like *conventional commit* format, but the scope has been restricted to a +JIRA issue format, i.e. `project-issueNumber`. This standardises scopes in a +meaningful way. + +It can be installed with `pip install conventional-JIRA`. From 78d3721ed6fd5a5e468e9a0dcd7fd1654f1a2dbb Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 24 Apr 2020 19:11:33 +0800 Subject: [PATCH 078/427] docs(readme): fix the display wording for Third-Party Commitizen Templates --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index cdeef31a76..dad2acf6bb 100644 --- a/docs/README.md +++ b/docs/README.md @@ -104,7 +104,7 @@ commands: ## Third-Party Commitizen Templates -See [docs/third-party-commitizen.md](third-party-commitizen.md). +See [Third-Party Commitizen Templates](third-party-commitizen.md). ## FAQ From 39b5778221d9a8b07e6e153c4231edad69284f29 Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 24 Apr 2020 19:26:10 +0800 Subject: [PATCH 079/427] docs(mkdocs): reorder nav bar and add Third-Party Commitizen Templates --- mkdocs.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index 46499871bc..3141eff34f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -10,16 +10,17 @@ edit_uri: "" nav: - Introduction: 'README.md' - - Configuration: 'config.md' - Commands: + - Init: 'init.md' - Bump: 'bump.md' - Check: 'check.md' - - Init: 'init.md' + - Configuration: 'config.md' - Customization: 'customization.md' - Tutorials: - Writing commits: 'tutorials/writing_commits.md' - GitLab CI: 'tutorials/gitlab_ci.md' - Github Actions: 'tutorials/github_actions.md' + - Third-Party Commitizen Templates: 'third-party-commitizen.md' markdown_extensions: - markdown.extensions.codehilite: From 4341fcd51da1eb86da2e53bd3da8241663a104af Mon Sep 17 00:00:00 2001 From: Wei Lee Date: Fri, 24 Apr 2020 20:10:05 +0800 Subject: [PATCH 080/427] docs: make contributing a separate page --- docs/README.md | 7 +------ docs/contributing.md | 20 ++++++++++++++++++++ mkdocs.yml | 1 + 3 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 docs/contributing.md diff --git a/docs/README.md b/docs/README.md index dad2acf6bb..29592f9529 100644 --- a/docs/README.md +++ b/docs/README.md @@ -124,12 +124,7 @@ git commit -m "revert: foo bar" ## Contributing -Feel free to create a PR. - -1. Clone the repo. -2. Add your modifications -3. Create a virtualenv -4. Run `./scripts/test` +See [Contributing](contributing.md) [conventional_commits]: https://www.conventionalcommits.org [semver]: https://semver.org/ diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 0000000000..14788790cb --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,20 @@ +## Contributing to commitizen + +First of all, thank you for taking the time to contribute! 🎉 + +When contributing to [commitizen](https://github.com/commitizen-tools/commitizen), please first create an [issue](https://github.com/commitizen-tools/commitizen/issues) to discuss the change you wish to make before making a change. + +If you're a first-time contributor, you can check the issues with [good first issue](https://github.com/commitizen-tools/commitizen/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) tag. + +## Before making a pull request + +1. Fork [the repository](https://github.com/commitizen-tools/commitizen) +2. Clone the repository from you GitHub +3. Setup development environment through [poetry](https://python-poetry.org/) (`poetry install`) +4. Check out a new branch and add your modification +5. Add test cases for all your changes + (We use [CodeCov](https://codecov.io/) to ensure our test coverage does not drop.) +6. Use [commitizen](https://github.com/commitizen-tools/commitizen) to do git commit +7. Run `./scripts/lint` and `./scripts/test` to ensure you follow the coding style and the tests pass +8. Update `READMD.md` and `CHANGELOG.md` for your changes +9. Send a [pull request](https://github.com/commitizen-tools/commitizen/pulls) 🙏 diff --git a/mkdocs.yml b/mkdocs.yml index 3141eff34f..42a03ca2ee 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -21,6 +21,7 @@ nav: - GitLab CI: 'tutorials/gitlab_ci.md' - Github Actions: 'tutorials/github_actions.md' - Third-Party Commitizen Templates: 'third-party-commitizen.md' + - Contributing: 'contributing.md' markdown_extensions: - markdown.extensions.codehilite: From 65d82683f6ef8fd90659c549860c13a01582e72a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= Date: Sun, 22 Mar 2020 21:35:08 +0100 Subject: [PATCH 081/427] refactor(changelog): rename category to change_type to fit 'keep a changelog' --- commitizen/changelog.py | 26 +++++++-------- .../conventional_commits.py | 2 ++ tests/test_changelog.py | 32 +++++++++---------- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/commitizen/changelog.py b/commitizen/changelog.py index b902640897..b5f29f2f98 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -22,10 +22,10 @@ from typing import Dict, Generator, Iterable, List MD_VERSION_RE = r"^##\s(?P[a-zA-Z0-9.+]+)\s?\(?(?P[0-9-]+)?\)?" -MD_CATEGORY_RE = r"^###\s(?P[a-zA-Z0-9.+\s]+)" +MD_CHANGE_TYPE_RE = r"^###\s(?P[a-zA-Z0-9.+\s]+)" MD_MESSAGE_RE = r"^-\s(\*{2}(?P[a-zA-Z0-9]+)\*{2}:\s)?(?P.+)" md_version_c = re.compile(MD_VERSION_RE) -md_category_c = re.compile(MD_CATEGORY_RE) +md_change_type_c = re.compile(MD_CHANGE_TYPE_RE) md_message_c = re.compile(MD_MESSAGE_RE) @@ -83,8 +83,8 @@ def parse_md_version(md_version: str) -> Dict: return m.groupdict() -def parse_md_category(md_category: str) -> Dict: - m = md_category_c.match(md_category) +def parse_md_change_type(md_change_type: str) -> Dict: + m = md_change_type_c.match(md_change_type) if not m: return {} return m.groupdict() @@ -97,31 +97,31 @@ def parse_md_message(md_message: str) -> Dict: return m.groupdict() -def transform_category(category: str) -> str: - _category_lower = category.lower() +def transform_change_type(change_type: str) -> str: + _change_type_lower = change_type.lower() for match_value, output in CATEGORIES: - if re.search(match_value, _category_lower): + if re.search(match_value, _change_type_lower): return output else: - raise ValueError(f"Could not match a category with {category}") + raise ValueError(f"Could not match a change_type with {change_type}") def generate_block_tree(block: List[str]) -> Dict: tree: Dict = {"commits": []} - category = None + change_type = None for line in block: if line.startswith("## "): - category = None + change_type = None tree = {**tree, **parse_md_version(line)} elif line.startswith("### "): - result = parse_md_category(line) + result = parse_md_change_type(line) if not result: continue - category = transform_category(result.get("category", "")) + change_type = transform_change_type(result.get("change_type", "")) elif line.startswith("- "): commit = parse_md_message(line) - commit["category"] = category + commit["change_type"] = change_type tree["commits"].append(commit) else: print("it's something else: ", line) diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index 8026532779..8dc4cec623 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -193,4 +193,6 @@ def info(self) -> str: def process_commit(self, commit: str) -> str: pat = re.compile(self.schema_pattern()) m = re.match(pat, commit) + if m is None: + return '' return m.group(3).strip() diff --git a/tests/test_changelog.py b/tests/test_changelog.py index dd34b9be92..8052832f25 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -102,8 +102,8 @@ def test_read_changelog_blocks(existing_changelog_file): CATEGORIES_CASES: list = [ ("## 1.0.0 (2019-07-12)", {}), ("## 2.3.0a0", {}), - ("### Bug fixes", {"category": "Bug fixes"}), - ("### Features", {"category": "Features"}), + ("### Bug fixes", {"change_type": "Bug fixes"}), + ("### Features", {"change_type": "Features"}), ("- issue in poetry add preventing the installation in py36", {}), ] CATEGORIES_TRANSFORMATIONS: list = [ @@ -133,13 +133,13 @@ def test_parse_md_version(test_input, expected): @pytest.mark.parametrize("test_input,expected", CATEGORIES_CASES) -def test_parse_md_category(test_input, expected): - assert changelog.parse_md_category(test_input) == expected +def test_parse_md_change_type(test_input, expected): + assert changelog.parse_md_change_type(test_input) == expected @pytest.mark.parametrize("test_input,expected", CATEGORIES_TRANSFORMATIONS) -def test_transform_category(test_input, expected): - assert changelog.transform_category(test_input) == expected +def test_transform_change_type(test_input, expected): + assert changelog.transform_change_type(test_input) == expected @pytest.mark.parametrize("test_input,expected", MESSAGES_CASES) @@ -147,10 +147,10 @@ def test_parse_md_message(test_input, expected): assert changelog.parse_md_message(test_input) == expected -def test_transform_category_fail(): +def test_transform_change_type_fail(): with pytest.raises(ValueError) as excinfo: - changelog.transform_category("Bugs") - assert "Could not match a category" in str(excinfo.value) + changelog.transform_change_type("Bugs") + assert "Could not match a change_type" in str(excinfo.value) def test_generate_block_tree(existing_changelog_file): @@ -162,16 +162,16 @@ def test_generate_block_tree(existing_changelog_file): { "scope": None, "message": "issue in poetry add preventing the installation in py36", - "category": "fix", + "change_type": "fix", }, - {"scope": "users", "message": "lorem ipsum apap", "category": "fix"}, + {"scope": "users", "message": "lorem ipsum apap", "change_type": "fix"}, { "scope": None, "message": ( "it is possible to specify a pattern to be matched " "in configuration files bump." ), - "category": "feat", + "change_type": "feat", }, ], "version": "1.0.0", @@ -191,23 +191,23 @@ def test_generate_full_tree(existing_changelog_file): "message": ( "issue in poetry add preventing the installation in py36" ), - "category": "fix", + "change_type": "fix", }, - {"scope": "users", "message": "lorem ipsum apap", "category": "fix"}, + {"scope": "users", "message": "lorem ipsum apap", "change_type": "fix"}, { "scope": None, "message": ( "it is possible to specify a pattern to be matched " "in configuration files bump." ), - "category": "feat", + "change_type": "feat", }, ], "version": "1.0.0", "date": "2019-07-12", }, { - "commits": [{"scope": None, "message": "holis", "category": "fix"}], + "commits": [{"scope": None, "message": "holis", "change_type": "fix"}], "version": "0.9", "date": "2019-07-11", }, From e0a1b49a30681b635ce8f5d559136bcaf81d18c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= Date: Sun, 19 Apr 2020 22:33:52 +0200 Subject: [PATCH 082/427] refactor(changelog): use functions from changelog.py --- CHANGELOG.md | 503 ++++++++-- commitizen/changelog.py | 189 ++-- commitizen/changelog_parser.py | 133 +++ commitizen/cli.py | 9 + commitizen/commands/changelog.py | 96 +- commitizen/cz/base.py | 1 + .../conventional_commits.py | 9 +- commitizen/defaults.py | 2 + commitizen/git.py | 15 +- .../templates/keep_a_changelog_template.j2 | 30 +- docs/changelog.md | 49 + pyproject.toml | 1 + tests/CHANGELOG_FOR_TEST.md | 129 +++ tests/commands/test_changelog_command.py | 11 +- tests/test_changelog.py | 865 ++++++++++++++---- tests/test_changelog_parser.py | 194 ++++ 16 files changed, 1816 insertions(+), 420 deletions(-) create mode 100644 commitizen/changelog_parser.py create mode 100644 docs/changelog.md create mode 100644 tests/CHANGELOG_FOR_TEST.md create mode 100644 tests/test_changelog_parser.py diff --git a/CHANGELOG.md b/CHANGELOG.md index d7d614abaf..b8736827ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,139 +1,504 @@ -# CHANGELOG -## v1.12.0 -### Feature +## Unreleased + +### Refactor + +- **changelog**: rename category to change_type to fit 'keep a changelog' +- **templates**: rename as "keep_a_changelog_template.j2" +- **templates**: remove unneeded __init__ file +- **cli**: reorder commands +- **templates**: move changelog_template from cz to templates +- **tests/utils**: move create_file_and_commit to tests/utils +- **commands/changelog**: remove redundant if statement +- **commands/changelog**: use jinja2 template instead of string concatenation to build changelog + +### Fix + +- **cz/conventional_commits**: fix schema_pattern break due to rebase +- **changelog_template**: fix list format +- **commitizen/cz**: set changelog_map, changelog_pattern to none as default +- **commands/changelog**: remove --skip-merge argument +- **cli**: add changelog arguments + +### Feat + +- **commands/changelog**: make changelog_file an option in config +- **commands/changelog**: exit when there is no commit exists +- **commands/changlog**: add --start-rev argument to `cz changelog` +- **changelog**: generate changelog based on git log +- **commands/changelog**: generate changelog_tree from all past commits +- **cz/conventinal_commits**: add changelog_map, changelog_pattern and implement process_commit +- **cz/base**: add default process_commit for processing commit message +- **changelog**: changelog tree generation from markdown + +## v1.17.0 (2020-03-15) + +### Refactor + +- **tests/bump**: use parameterize to group similliar tests +- **cz/connventional_commit**: use \S to check scope +- **git**: remove unnecessary dot between git range + +### Fix + +- **bump**: fix bump find_increment error + +### Feat + +- **commands/check**: add --rev-range argument for checking commits within some range + +## v1.16.4 (2020-03-03) + +### Fix + +- **commands/init**: fix clean up file when initialize commitizen config + +### Refactor + +- **defaults**: split config files into long term support and deprecated ones + +## v1.16.3 (2020-02-20) + +### Fix + +- replace README.rst with docs/README.md in config files + +### Refactor + +- **docs**: remove README.rst and use docs/README.md + +## v1.16.2 (2020-02-01) + +### Fix + +- **commands/check**: add bump into valid commit message of convention commit pattern + +## v1.16.1 (2020-02-01) + +### Fix + +- **pre-commit**: set pre-commit check stage to commit-msg + +## v1.16.0 (2020-01-21) + +### Refactor + +- **commands/bump**: rename parameter into bump_setting to distinguish bump_setting and argument +- **git**: rename get tag function to distinguish return str and GitTag +- **cmd**: reimplement how cmd is run +- **git**: Use GitCommit, GitTag object to store commit and git information +- **git**: make arguments other then start and end in get_commit keyword arguments +- **git**: Change get_commits into returning commits instead of lines of messsages + +### Feat + +- **git**: get_commits default from first_commit + +## v1.15.1 (2020-01-20) + +## v1.15.0 (2020-01-20) + +### Refactor + +- **tests/commands/bump**: use tmp_dir to replace self implemented tmp dir behavior +- **test_bump_command**: rename camel case variables +- **tests/commands/check**: use pytest fixture tmpdir replace self implemented contextmanager +- **test/commands/other**: replace unit test style mock with mocker fixture +- **tests/commands**: separate command unit tests into modules +- **tests/commands**: make commands related tests a module +- **git**: make find_git_project_root return None if it's not a git project +- **config/base_config**: make set_key not implemented +- **error_codes**: move all the error_codes to a module +- **config**: replace string type path with pathlib.Path + +### Fix + +- **cli**: fix --version not functional +- **git**: remove breakline in the return value of find_git_project_root + +### Feat + +- **config**: look up configuration in git project root +- **git**: add find_git_project_root + +## v1.14.2 (2020-01-14) + +### Fix + +- **github_workflow/pythonpublish**: use peaceiris/actions-gh-pages@v2 to publish docs + +## v1.14.1 (2020-01-11) + +## v1.14.0 (2020-01-06) + +### Refactor + +- **pre-commit-hooks**: add metadata for the check hook + +### Feat + +- **pre-commit-hooks**: add pre-commit hook + +### Fix + +- **cli**: fix the way default handled for name argument +- **cli**: fix name cannot be overwritten through config in newly refactored config design + +## v1.13.1 (2019-12-31) + +### Fix + +- **github_workflow/pythonpackage**: set git config for unit testing +- **scripts/test**: ensure the script fails once the first failure happens + +## v1.13.0 (2019-12-30) + +### Feat + +- add project version to command init + +## v1.12.0 (2019-12-30) + +### Feat - new init command -## v1.11.0 +## v1.10.3 (2019-12-29) -Ignore this version +### Refactor -## v1.10.0 +- **commands/bump**: use "version_files" internally +- **config**: set "files" to alias of "version_files" -### Feature +## v1.10.2 (2019-12-27) -- new argument `--files-only` in bump +### Refactor -## v1.9.2 +- new config system where each config type has its own class +- **config**: add type annotation to config property +- **config**: fix wrongly type annoated functions +- **config/ini_config**: move deprecation warning into class initialization +- **config**: use add_path instead of directly assigning _path +- **all**: replace all the _settings invoke with settings.update +- **cz/customize**: remove unnecessary statement "raise NotImplementedError("Not Implemented yet")" +- **config**: move default settings back to defaults +- **config**: Make config a class and each type of config (e.g., toml, ini) a child class ### Fix -- `--commit-msg-file` is now a required argument +- **config**: handle empty config file +- **config**: fix load global_conf even if it doesn't exist +- **config/ini_config**: replase outdated _parse_ini_settings with _parse_settings -## v1.9.1 +## v1.10.1 (2019-12-10) ### Fix -- exception `AnswerRequiredException` not caught +- **cli**: overwrite "name" only when it's not given +- **config**: fix typo -## v1.9.0 +## v1.10.0 (2019-11-28) -### Feature +### Feat -- 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`. +- support for different commitizens in `cz check` +- **bump**: new argument --files-only +## v1.9.2 (2019-11-23) ### Fix -- tests were fixed -- windows error when removing folders (#67) -- typos in docs +- **commands/check.py**: --commit-msg-file is now a required argument -### Docs -- tutorial for gitlab ci -- tutorial for github actions +## v1.9.1 (2019-11-23) -## v1.8.0 +### Fix -### Feature +- **cz/exceptions**: exception AnswerRequiredException not caught (#89) -- new custom exception for commitizen -- commit is aborted if nothing in staging +## v1.9.0 (2019-11-22) -## v1.7.0 +### Feat -### Feature +- **Commands/check**: enforce the project to always use conventional commits +- **config**: add deprecation warning for loading config from ini files +- **cz/customize**: add jinja support to enhance template flexibility +- **cz/filters**: add required_validator and multiple_line_breaker +- **Commands/commit**: add ´--dry-run´ flag to the Commit command +- **cz/cz_customize**: implement info to support info and info_path +- **cz/cz_customize**: enable bump_pattern bump_map customization +- **cz/cz_customize**: implement customizable cz +- new 'git-cz' entrypoint -- new styles for the prompt -- new configuration option for the prompt styles +### Refactor -## v1.6.0 +- **config**: remove has_pyproject which is no longer used +- **cz/customize**: make jinja2 a custom requirement. if not installed use string.Tempalte instead +- **cz/utils**: rename filters as utils +- **cli**: add back --version and remove subcommand required constraint -### Feature +### Fix -- new retry argument to execute previous commit again +- commit dry-run doesnt require staging to be clean +- correct typo to spell "convention" +- removing folder in windows throwing a PermissionError +- **scripts**: add back the delelte poetry prefix +- **test_cli**: testing the version command -## v1.5.1 +## v1.8.0 (2019-11-12) ### Fix -- issue in poetry add preventing the installation in py36 +- **commands/commit**: catch exception raised by customization cz +- **cli**: handle the exception that command is not given +- **cli**: enforce subcommand as required + +### Refactor + +- **cz/conventional_commit**: make NoSubjectException inherit CzException and add error message +- **command/version**: use out.write instead of out.line +- **command**: make version a command instead of an argument + +### Feat + +- **cz**: add a base exception for cz customization +- **commands/commit**: abort commit if there is nothing to commit +- **git**: add is_staging_clean to check if there is any file in git staging + +## v1.7.0 (2019-11-08) + +### Fix + +- **cz**: fix bug in BaseCommitizen.style +- **cz**: fix merge_style usage error +- **cz**: remove breakpoint + +### Refactor + +- **cz**: change the color of default style + +### Feat + +- **config**: update style instead of overwrite +- **config**: parse style in config +- **commit**: make style configurable for commit command -## v1.5.0 +## v1.6.0 (2019-11-05) -### Feature +### Feat -- it is possible to specify a pattern to be matched in configuration `files` when doing bump. +- **commit**: new retry argument to execute previous commit again -## v1.4.0 +## v1.5.1 (2019-06-04) -### Feature +### Fix + +- #28 allows poetry add on py36 envs + +## v1.5.0 (2019-05-11) -- new argument (--yes) in bump to accept prompt questions +### Feat + +- **bump**: it is now possible to specify a pattern in the files attr to replace the version + +## v1.4.0 (2019-04-26) ### Fix -- error is shown when commiting fails. +- **bump**: handle commit and create tag failure + +### Feat -## v1.3.0 +- added argument yes to bump in order to accept questions -### Feature +## v1.3.0 (2019-04-24) -- bump: new commit message template, useful when having to skip ci. +### Feat -## v1.2.1 +- **bump**: new commit message template + +## v1.2.1 (2019-04-21) ### Fix -- prefixes like docs, build, etc no longer generate a PATCH +- **bump**: prefixes like docs, build, etc no longer generate a PATCH -## v1.2.0 +## v1.2.0 (2019-04-19) -### Feature +### Feat - custom cz plugins now support bumping version -## v1.1.1 +## v1.1.1 (2019-04-18) + +### Refactor + +- changed stdout statements +- **schema**: command logic removed from commitizen base +- **info**: command logic removed from commitizen base +- **example**: command logic removed from commitizen base +- **commit**: moved most of the commit logic to the commit command + +### Fix + +- **bump**: commit message now fits better with semver +- conventional commit 'breaking change' in body instead of title + +## v1.1.0 (2019-04-14) + +### Feat + +- new working bump command +- create version tag +- update given files with new version +- **config**: new set key, used to set version to cfg +- support for pyproject.toml +- first semantic version bump implementaiton ### Fix -- breaking change is now part of the body, instead of being in the subject +- removed all from commit +- fix config file not working + +### Refactor + +- added commands folder, better integration with decli + +## v1.0.0 (2019-03-01) + +### Refactor + +- removed delegator, added decli and many tests + +## 1.0.0b2 (2019-01-18) + +## v1.0.0b1 (2019-01-17) + +### Feat + +- py3 only, tests and conventional commits 1.0 + +## v0.9.11 (2018-12-17) + +### Fix + +- **config**: load config reads in order without failing if there is no commitizen section + +## v0.9.10 (2018-09-22) + +### Fix + +- parse scope (this is my punishment for not having tests) + +## v0.9.9 (2018-09-22) + +### Fix + +- parse scope empty + +## v0.9.8 (2018-09-22) + +### Fix + +- **scope**: parse correctly again + +## v0.9.7 (2018-09-22) + +### Fix + +- **scope**: parse correctly + +## v0.9.6 (2018-09-19) + +### Refactor + +- **conventionalCommit**: moved fitlers to questions instead of message + +### Fix + +- **manifest**: inluded missing files + +## v0.9.5 (2018-08-24) + +### Fix + +- **config**: home path for python versions between 3.0 and 3.5 + +## v0.9.4 (2018-08-02) + +### Feat + +- **cli**: added version + +## v0.9.3 (2018-07-28) + +### Feat + +- **commiter**: conventional commit is a bit more intelligent now + +## v0.9.2 (2017-11-11) + +### Refactor + +- **renamed conventional_changelog to conventional_commits, not backward compatible**: + +## v0.9.1 (2017-11-11) + +### Fix + +- **setup.py**: future is now required for every python version + +## v0.9.0 (2017-11-08) + +### Refactor + +- python 2 support + +## v0.8.6 (2017-11-08) + +## v0.8.5 (2017-11-08) + +## v0.8.4 (2017-11-08) + +## v0.8.3 (2017-11-08) + +## v0.8.2 (2017-10-08) + +## v0.8.1 (2017-10-08) + +## v0.8.0 (2017-10-08) + +### Feat + +- **cz**: jira smart commits + +## v0.7.0 (2017-10-08) + +### Refactor + +- **cli**: renamed all to ls command +- **cz**: renamed angular cz to conventional changelog cz + +## v0.6.0 (2017-10-08) + +### Feat + +- info command for angular -## v1.1.0 +## v0.5.0 (2017-10-07) -### Features +## v0.4.0 (2017-10-07) -- auto bump version based on conventional commits using sem ver -- pyproject support (see [pyproject.toml](./pyproject.toml) for usage) +## v0.3.0 (2017-10-07) -## v1.0.0 +## v0.2.0 (2017-10-07) -### Features +### Feat -- more documentation -- added tests -- support for conventional commits 1.0.0 +- **config**: new loads from ~/.cz and working project .cz .cz.cfg and setup.cfg +- package discovery -### BREAKING CHANGES +### Refactor -- use of questionary to generate the prompt (so we depend on promptkit 2.0) -- python 3 only +- **cz_angular**: improved messages diff --git a/commitizen/changelog.py b/commitizen/changelog.py index b5f29f2f98..25d090b7dd 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -1,33 +1,35 @@ """ # DESIGN -## Parse CHANGELOG.md +## Metadata CHANGELOG.md -1. Get LATEST VERSION from CONFIG -1. Parse the file version to version -2. Build a dict (tree) of that particular version -3. Transform tree into markdown again +1. Identify irrelevant information (possible: changelog title, first paragraph) +2. Identify Unreleased area +3. Identify latest version (to be able to write on top of it) ## Parse git log 1. get commits between versions 2. filter commits with the current cz rules 3. parse commit information -4. generate tree +4. yield tree nodes +5. format tree nodes +6. produce full tree +7. generate changelog -Options: +Extra: - Generate full or partial changelog +- Include in tree from file all the extra comments added manually """ import re -from typing import Dict, Generator, Iterable, List +from collections import defaultdict +from typing import Dict, Iterable, List, Optional -MD_VERSION_RE = r"^##\s(?P[a-zA-Z0-9.+]+)\s?\(?(?P[0-9-]+)?\)?" -MD_CHANGE_TYPE_RE = r"^###\s(?P[a-zA-Z0-9.+\s]+)" -MD_MESSAGE_RE = r"^-\s(\*{2}(?P[a-zA-Z0-9]+)\*{2}:\s)?(?P.+)" -md_version_c = re.compile(MD_VERSION_RE) -md_change_type_c = re.compile(MD_CHANGE_TYPE_RE) -md_message_c = re.compile(MD_MESSAGE_RE) +import pkg_resources +from jinja2 import Template +from commitizen import defaults +from commitizen.git import GitCommit, GitProtocol, GitTag CATEGORIES = [ ("fix", "fix"), @@ -42,62 +44,9 @@ ] -def find_version_blocks(filepath: str) -> Generator: - """ - version block: contains all the information about a version. - - E.g: - ``` - ## 1.2.1 (2019-07-20) - - ## Bug fixes - - - username validation not working - - ## Features - - - new login system - - ``` - """ - with open(filepath, "r") as f: - block: list = [] - for line in f: - line = line.strip("\n") - if not line: - continue - - if line.startswith("## "): - if len(block) > 0: - yield block - block = [line] - else: - block.append(line) - yield block - - -def parse_md_version(md_version: str) -> Dict: - m = md_version_c.match(md_version) - if not m: - return {} - return m.groupdict() - - -def parse_md_change_type(md_change_type: str) -> Dict: - m = md_change_type_c.match(md_change_type) - if not m: - return {} - return m.groupdict() - - -def parse_md_message(md_message: str) -> Dict: - m = md_message_c.match(md_message) - if not m: - return {} - return m.groupdict() - - def transform_change_type(change_type: str) -> str: + # TODO: Use again to parse, for this we have to wait until the maps get + # defined again. _change_type_lower = change_type.lower() for match_value, output in CATEGORIES: if re.search(match_value, _change_type_lower): @@ -106,28 +55,80 @@ def transform_change_type(change_type: str) -> str: raise ValueError(f"Could not match a change_type with {change_type}") -def generate_block_tree(block: List[str]) -> Dict: - tree: Dict = {"commits": []} - change_type = None - for line in block: - if line.startswith("## "): - change_type = None - tree = {**tree, **parse_md_version(line)} - elif line.startswith("### "): - result = parse_md_change_type(line) - if not result: - continue - change_type = transform_change_type(result.get("change_type", "")) - - elif line.startswith("- "): - commit = parse_md_message(line) - commit["change_type"] = change_type - tree["commits"].append(commit) - else: - print("it's something else: ", line) - return tree - - -def generate_full_tree(blocks: Iterable) -> Iterable[Dict]: - for block in blocks: - yield generate_block_tree(block) +def get_commit_tag(commit: GitProtocol, tags: List[GitProtocol]) -> Optional[GitTag]: + """""" + try: + tag_index = tags.index(commit) + except ValueError: + return None + else: + tag = tags[tag_index] + return tag + + +def generate_tree_from_commits( + commits: List[GitCommit], + tags: List[GitTag], + commit_parser: str, + changelog_pattern: str = defaults.bump_pattern, +) -> Iterable[Dict]: + pat = re.compile(changelog_pattern) + map_pat = re.compile(commit_parser) + # Check if the latest commit is not tagged + latest_commit = commits[0] + current_tag: Optional[GitTag] = get_commit_tag(latest_commit, tags) + + current_tag_name: str = "Unreleased" + current_tag_date: str = "" + if current_tag is not None and current_tag.name: + current_tag_name = current_tag.name + current_tag_date = current_tag.date + + changes: Dict = defaultdict(list) + used_tags: List = [current_tag] + for commit in commits: + commit_tag = get_commit_tag(commit, tags) + + if commit_tag is not None and commit_tag not in used_tags: + used_tags.append(commit_tag) + yield { + "version": current_tag_name, + "date": current_tag_date, + "changes": changes, + } + # TODO: Check if tag matches the version pattern, otherwie skip it. + # This in order to prevent tags that are not versions. + current_tag_name = commit_tag.name + current_tag_date = commit_tag.date + changes = defaultdict(list) + + matches = pat.match(commit.message) + if not matches: + continue + + message = map_pat.match(commit.message) + message_body = map_pat.match(commit.body) + if message: + parsed_message: Dict = message.groupdict() + # change_type becomes optional by providing None + change_type = parsed_message.pop("change_type", None) + changes[change_type].append(parsed_message) + if message_body: + parsed_message_body: Dict = message_body.groupdict() + change_type = parsed_message_body.pop("change_type", None) + changes[change_type].append(parsed_message_body) + + yield { + "version": current_tag_name, + "date": current_tag_date, + "changes": changes, + } + + +def render_changelog(tree: Iterable) -> str: + template_file = pkg_resources.resource_string( + __name__, "templates/keep_a_changelog_template.j2" + ).decode("utf-8") + jinja_template = Template(template_file, trim_blocks=True) + changelog: str = jinja_template.render(tree=tree) + return changelog diff --git a/commitizen/changelog_parser.py b/commitizen/changelog_parser.py new file mode 100644 index 0000000000..c945cbdb4f --- /dev/null +++ b/commitizen/changelog_parser.py @@ -0,0 +1,133 @@ +""" +# DESIGN + +## Parse CHANGELOG.md + +1. Get LATEST VERSION from CONFIG +1. Parse the file version to version +2. Build a dict (tree) of that particular version +3. Transform tree into markdown again +""" +import re +from collections import defaultdict +from typing import Dict, Generator, Iterable, List + +MD_VERSION_RE = r"^##\s(?P[a-zA-Z0-9.+]+)\s?\(?(?P[0-9-]+)?\)?" +MD_CHANGE_TYPE_RE = r"^###\s(?P[a-zA-Z0-9.+\s]+)" +MD_MESSAGE_RE = ( + r"^-\s(\*{2}(?P[a-zA-Z0-9]+)\*{2}:\s)?(?P.+)(?P!)?" +) +md_version_c = re.compile(MD_VERSION_RE) +md_change_type_c = re.compile(MD_CHANGE_TYPE_RE) +md_message_c = re.compile(MD_MESSAGE_RE) + + +CATEGORIES = [ + ("fix", "fix"), + ("breaking", "BREAKING CHANGES"), + ("feat", "feat"), + ("refactor", "refactor"), + ("perf", "perf"), + ("test", "test"), + ("build", "build"), + ("ci", "ci"), + ("chore", "chore"), +] + + +def find_version_blocks(filepath: str) -> Generator: + """ + version block: contains all the information about a version. + + E.g: + ``` + ## 1.2.1 (2019-07-20) + + ### Fix + + - username validation not working + + ### Feat + + - new login system + + ``` + """ + with open(filepath, "r") as f: + block: list = [] + for line in f: + line = line.strip("\n") + if not line: + continue + + if line.startswith("## "): + if len(block) > 0: + yield block + block = [line] + else: + block.append(line) + yield block + + +def parse_md_version(md_version: str) -> Dict: + m = md_version_c.match(md_version) + if not m: + return {} + return m.groupdict() + + +def parse_md_change_type(md_change_type: str) -> Dict: + m = md_change_type_c.match(md_change_type) + if not m: + return {} + return m.groupdict() + + +def parse_md_message(md_message: str) -> Dict: + m = md_message_c.match(md_message) + if not m: + return {} + return m.groupdict() + + +def transform_change_type(change_type: str) -> str: + # TODO: Use again to parse, for this we have to wait until the maps get + # defined again. + _change_type_lower = change_type.lower() + for match_value, output in CATEGORIES: + if re.search(match_value, _change_type_lower): + return output + else: + raise ValueError(f"Could not match a change_type with {change_type}") + + +def generate_block_tree(block: List[str]) -> Dict: + # tree: Dict = {"commits": []} + changes: Dict = defaultdict(list) + tree: Dict = {"changes": changes} + + change_type = None + for line in block: + if line.startswith("## "): + # version identified + change_type = None + tree = {**tree, **parse_md_version(line)} + elif line.startswith("### "): + # change_type identified + result = parse_md_change_type(line) + if not result: + continue + change_type = result.get("change_type", "").lower() + + elif line.startswith("- "): + # message identified + commit = parse_md_message(line) + changes[change_type].append(commit) + else: + print("it's something else: ", line) + return tree + + +def generate_full_tree(blocks: Iterable) -> Iterable[Dict]: + for block in blocks: + yield generate_block_tree(block) diff --git a/commitizen/cli.py b/commitizen/cli.py index 9d5130dce9..94eb2ca845 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -131,6 +131,15 @@ "default": False, "help": "show changelog to stdout", }, + { + "name": "--incremental", + "action": "store_true", + "default": False, + "help": ( + "generates changelog from last created version, " + "useful if the changelog has been manually modified" + ), + }, { "name": "--file-name", "help": "file name of changelog (default: 'CHANGELOG.md')", diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index b9bd966d27..016c320a31 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -4,9 +4,9 @@ import pkg_resources from jinja2 import Template -from commitizen import factory, git, out +from commitizen import changelog, factory, git, out from commitizen.config import BaseConfig -from commitizen.error_codes import NO_COMMITS_FOUND, NO_PATTERN_MAP +from commitizen.error_codes import NO_COMMITS_FOUND, NO_PATTERN_MAP, TAG_FAILED class Changelog: @@ -17,63 +17,73 @@ def __init__(self, config: BaseConfig, args): self.cz = factory.commiter_factory(self.config) self.file_name = args["file_name"] or self.config.settings.get("changelog_file") + self.incremental = args["incremental"] self.dry_run = args["dry_run"] self.start_rev = args["start_rev"] def __call__(self): - changelog_map = self.cz.changelog_map + # changelog_map = self.cz.changelog_map + commit_parser = self.cz.commit_parser changelog_pattern = self.cz.changelog_pattern - if not changelog_map or not changelog_pattern: + + if not changelog_pattern or not commit_parser: out.error( f"'{self.config.settings['name']}' rule does not support changelog" ) raise SystemExit(NO_PATTERN_MAP) - - pat = re.compile(changelog_pattern) + # pat = re.compile(changelog_pattern) commits = git.get_commits(start=self.start_rev) if not commits: out.error("No commits found") raise SystemExit(NO_COMMITS_FOUND) - tag_map = {tag.rev: tag.name for tag in git.get_tags()} - - entries = OrderedDict() - # The latest commit is not tagged - latest_commit = commits[0] - if latest_commit.rev not in tag_map: - current_key = "Unreleased" - entries[current_key] = OrderedDict( - {value: [] for value in changelog_map.values()} - ) - else: - current_key = tag_map[latest_commit.rev] - - for commit in commits: - if commit.rev in tag_map: - current_key = tag_map[commit.rev] - entries[current_key] = OrderedDict( - {value: [] for value in changelog_map.values()} - ) - - matches = pat.match(commit.message) - if not matches: - continue - - processed_commit = self.cz.process_commit(commit.message) - for group_name, commit_type in changelog_map.items(): - if matches.group(group_name): - entries[current_key][commit_type].append(processed_commit) - break - - template_file = pkg_resources.resource_string( - __name__, "../templates/keep_a_changelog_template.j2" - ).decode("utf-8") - jinja_template = Template(template_file) - changelog_str = jinja_template.render(entries=entries) + tags = git.get_tags() + if not tags: + tags = [] + + tree = changelog.generate_tree_from_commits( + commits, tags, commit_parser, changelog_pattern + ) + changelog_out = changelog.render_changelog(tree) + # tag_map = {tag.rev: tag.name for tag in git.get_tags()} + + # entries = OrderedDict() + # # The latest commit is not tagged + # latest_commit = commits[0] + # if latest_commit.rev not in tag_map: + # current_key = "Unreleased" + # entries[current_key] = OrderedDict( + # {value: [] for value in changelog_map.values()} + # ) + # else: + # current_key = tag_map[latest_commit.rev] + + # for commit in commits: + # if commit.rev in tag_map: + # current_key = tag_map[commit.rev] + # entries[current_key] = OrderedDict( + # {value: [] for value in changelog_map.values()} + # ) + + # matches = pat.match(commit.message) + # if not matches: + # continue + + # processed_commit = self.cz.process_commit(commit.message) + # for group_name, commit_type in changelog_map.items(): + # if matches.group(group_name): + # entries[current_key][commit_type].append(processed_commit) + # break + + # template_file = pkg_resources.resource_string( + # __name__, "../templates/keep_a_changelog_template.j2" + # ).decode("utf-8") + # jinja_template = Template(template_file) + # changelog_str = jinja_template.render(entries=entries) if self.dry_run: - out.write(changelog_str) + out.write(changelog_out) raise SystemExit(0) with open(self.file_name, "w") as changelog_file: - changelog_file.write(changelog_str) + changelog_file.write(changelog_out) diff --git a/commitizen/cz/base.py b/commitizen/cz/base.py index ff6147d29f..207be89d1d 100644 --- a/commitizen/cz/base.py +++ b/commitizen/cz/base.py @@ -23,6 +23,7 @@ class BaseCommitizen(metaclass=ABCMeta): ("text", ""), ("disabled", "fg:#858585 italic"), ] + commit_parser: Optional[str] = None def __init__(self, config: BaseConfig): self.config = config diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index 8dc4cec623..b932bd6682 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -1,6 +1,5 @@ import os import re -from collections import OrderedDict from typing import Any, Dict, List from commitizen import defaults @@ -31,10 +30,8 @@ def parse_subject(text): class ConventionalCommitsCz(BaseCommitizen): bump_pattern = defaults.bump_pattern bump_map = defaults.bump_map - changelog_pattern = ( - r"(?P.*\n\nBREAKING CHANGE)|(?P^feat)|(?P^fix)" - ) - changelog_map = OrderedDict({"break": "breaking", "feat": "feat", "fix": "fix"}) + commit_parser = defaults.commit_parser + changelog_pattern = defaults.bump_pattern def questions(self) -> List[Dict[str, Any]]: questions: List[Dict[str, Any]] = [ @@ -194,5 +191,5 @@ def process_commit(self, commit: str) -> str: pat = re.compile(self.schema_pattern()) m = re.match(pat, commit) if m is None: - return '' + return "" return m.group(3).strip() diff --git a/commitizen/defaults.py b/commitizen/defaults.py index a694a11840..070b415646 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -32,3 +32,5 @@ ) ) bump_message = "bump: version $current_version → $new_version" + +commit_parser = r"^(?Pfeat|fix|refactor|perf|BREAKING CHANGE)(?:\((?P[^()\r\n]*)\)|\()?(?P!)?:\s(?P.*)?" # noqa diff --git a/commitizen/git.py b/commitizen/git.py index 058ba89a00..feac0697b0 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -3,12 +3,21 @@ from tempfile import NamedTemporaryFile from typing import List, Optional +from typing_extensions import Protocol + from commitizen import cmd +class GitProtocol(Protocol): + rev: str + name: str + + class GitObject: - def __eq__(self, other): - if not isinstance(other, GitObject): + rev: str + + def __eq__(self, other) -> bool: + if not hasattr(other, "rev"): return False return self.rev == other.rev @@ -34,7 +43,7 @@ def __init__(self, name, rev, date): self.date = date.strip() def __repr__(self): - return f"{self.name} ({self.rev})" + return f"GitTag('{self.name}', '{self.rev}', '{self.date}')" def tag(tag: str): diff --git a/commitizen/templates/keep_a_changelog_template.j2 b/commitizen/templates/keep_a_changelog_template.j2 index d3fba14668..a0fadb0223 100644 --- a/commitizen/templates/keep_a_changelog_template.j2 +++ b/commitizen/templates/keep_a_changelog_template.j2 @@ -1,13 +1,19 @@ -# CHANGELOG - -{% for entry_key, entry_value in entries.items() -%} -## {{entry_key}} -{% for type, commits in entry_value.items() -%} -{%- if commits -%} -### {{type}} -{% for commit in commits-%} -- {{commit}} -{% endfor %} +{% for entry in tree %} + +## {{ entry.version }} {% if entry.date %}({{ entry.date }}){% endif %} + +{% for change_key, changes in entry.changes.items() %} + +{% if change_key %} +### {{ change_key|title }} {% endif %} -{%- endfor %} -{%- endfor %} + +{% for change in changes %} +{% if change.scope %} +- **{{ change.scope }}**: {{ change.message }} +{% else %} +- {{ change.message }} +{% endif %} +{% endfor %} +{% endfor %} +{% endfor %} diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 0000000000..db8d0bc6ed --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,49 @@ +## About + +This command will generate a changelog following the commiting rules established. + +## Usage + +In the command line run + +```bash +cz changelog +``` + +```bash +cz ch +``` + +## Description + +These are the variables used by the changelog generator. + +```md +# () + +## + +- ****: +``` + +It will create a full of the above block per version found in the tags. +And it will create a list of the commits found. +The `change_type` and the `scope` are optional, they don't need to be provided, +but if your regex does they will be rendered. + +The format followed by the changelog is the one from [keep a changelog][keepachangelog] +and the following variables are expected: + +| Variable | Description | Source | +| ------------- | ---------------------------------------------------------------------------------------------- | -------------- | +| `version` | Version number which should follow [semver][semver] | `tags` | +| `date` | Date in which the tag was created | `tags` | +| `change_type` | The group where the commit belongs to, this is optional. Example: fix | `commit regex` | +| `message`\* | Information extracted from the commit message | `commit regex` | +| `scope` | Contextual information. Should be parsed using the regex from the message, it will be **bold** | `commit regex` | +| `breaking` | Wether is a breaking change or not | `commit regex` | + +- **required**: is the only one required to be parsed by the regex + +[keepachangelog]: https://keepachangelog.com/ +[semver]: https://semver.org/ diff --git a/pyproject.toml b/pyproject.toml index 97add2bf9c..7a2685a783 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,6 +52,7 @@ termcolor = "^1.1" packaging = ">=19,<21" tomlkit = "^0.5.3" jinja2 = "^2.10.3" +typing = "^3.7.4" [tool.poetry.dev-dependencies] ipython = "^7.2" diff --git a/tests/CHANGELOG_FOR_TEST.md b/tests/CHANGELOG_FOR_TEST.md new file mode 100644 index 0000000000..7605bbed47 --- /dev/null +++ b/tests/CHANGELOG_FOR_TEST.md @@ -0,0 +1,129 @@ + +## v1.2.0 (2019-04-19) + +### Feat + +- custom cz plugins now support bumping version + +## v1.1.1 (2019-04-18) + +### Refactor + +- changed stdout statements +- **schema**: command logic removed from commitizen base +- **info**: command logic removed from commitizen base +- **example**: command logic removed from commitizen base +- **commit**: moved most of the commit logic to the commit command + +### Fix + +- **bump**: commit message now fits better with semver +- conventional commit 'breaking change' in body instead of title + +## v1.1.0 (2019-04-14) + +### Feat + +- new working bump command +- create version tag +- update given files with new version +- **config**: new set key, used to set version to cfg +- support for pyproject.toml +- first semantic version bump implementaiton + +### Fix + +- removed all from commit +- fix config file not working + +### Refactor + +- added commands folder, better integration with decli + +## v1.0.0 (2019-03-01) + +### Refactor + +- removed delegator, added decli and many tests + +### Breaking Change + +- API is stable + +## 1.0.0b2 (2019-01-18) + +## v1.0.0b1 (2019-01-17) + +### Feat + +- py3 only, tests and conventional commits 1.0 + +## v0.9.11 (2018-12-17) + +### Fix + +- **config**: load config reads in order without failing if there is no commitizen section + +## v0.9.10 (2018-09-22) + +### Fix + +- parse scope (this is my punishment for not having tests) + +## v0.9.9 (2018-09-22) + +### Fix + +- parse scope empty + +## v0.9.8 (2018-09-22) + +### Fix + +- **scope**: parse correctly again + +## v0.9.7 (2018-09-22) + +### Fix + +- **scope**: parse correctly + +## v0.9.6 (2018-09-19) + +### Refactor + +- **conventionalCommit**: moved fitlers to questions instead of message + +### Fix + +- **manifest**: inluded missing files + +## v0.9.5 (2018-08-24) + +### Fix + +- **config**: home path for python versions between 3.0 and 3.5 + +## v0.9.4 (2018-08-02) + +### Feat + +- **cli**: added version + +## v0.9.3 (2018-07-28) + +### Feat + +- **commiter**: conventional commit is a bit more intelligent now + +## v0.9.2 (2017-11-11) + +### Refactor + +- renamed conventional_changelog to conventional_commits, not backward compatible + +## v0.9.1 (2017-11-11) + +### Fix + +- **setup.py**: future is now required for every python version diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index a053e6c238..981cfa654c 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -28,7 +28,11 @@ def test_changlog_from_start(mocker, capsys): cli.main() out, _ = capsys.readouterr() - assert out == "# CHANGELOG\n\n## Unreleased\n### feat\n- new file\n\n\n" + + assert ( + out + == "\n## Unreleased \n\n### Refactor\n\n- not in changelog\n\n### Feat\n\n- new file\n\n" + ) @pytest.mark.usefixtures("tmp_commitizen_project") @@ -51,10 +55,7 @@ def test_changlog_from_version_zero_point_two(mocker, capsys): cli.main() out, _ = capsys.readouterr() - assert ( - out - == "# CHANGELOG\n\n## Unreleased\n### feat\n- after 0.2\n- after 0.2.0\n\n\n" - ) + assert out == "\n## Unreleased \n\n### Feat\n\n- after 0.2\n- after 0.2.0\n\n" @pytest.mark.usefixtures("tmp_commitizen_project") diff --git a/tests/test_changelog.py b/tests/test_changelog.py index 8052832f25..94c3c47017 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -1,214 +1,703 @@ -import os - import pytest -from commitizen import changelog - -COMMIT_LOG = [ - "bump: version 1.5.0 → 1.5.1", - "", - "Merge pull request #29 from esciara/issue_28", - "fix: #28 allows poetry add on py36 envs", - "fix: #28 allows poetry add on py36 envs", - "", - "Merge pull request #26 from Woile/dependabot/pip/black-tw-19.3b0", - "chore(deps-dev): update black requirement from ^18.3-alpha.0 to ^19.3b0", - "Merge pull request #27 from Woile/dependabot/pip/mypy-tw-0.701", - "chore(deps-dev): update mypy requirement from ^0.700.0 to ^0.701", - "chore(deps-dev): update mypy requirement from ^0.700.0 to ^0.701", - ( - "Updates the requirements on " - "[mypy](https://github.com/python/mypy) to permit the latest version." - ), - "- [Release notes](https://github.com/python/mypy/releases)", - "- [Commits](https://github.com/python/mypy/compare/v0.700...v0.701)", - "", - "Signed-off-by: dependabot[bot] ", - "chore(deps-dev): update black requirement from ^18.3-alpha.0 to ^19.3b0", - ( - "Updates the requirements on [black](https://github.com/ambv/black)" - " to permit the latest version." - ), - "- [Release notes](https://github.com/ambv/black/releases)", - "- [Commits](https://github.com/ambv/black/commits)", - "", - "Signed-off-by: dependabot[bot] ", - "bump: version 1.4.0 → 1.5.0", - "", - "docs: add info about extra pattern in the files when bumping", - "", - ( - "feat(bump): it is now possible to specify a pattern " - "in the files attr to replace the version" - ), - "", +from commitizen import changelog, defaults, git + +COMMITS_DATA = [ + { + "rev": "141ee441c9c9da0809c554103a558eb17c30ed17", + "title": "bump: version 1.1.1 → 1.2.0", + "body": "", + }, + { + "rev": "6c4948501031b7d6405b54b21d3d635827f9421b", + "title": "docs: how to create custom bumps", + "body": "", + }, + { + "rev": "ddd220ad515502200fe2dde443614c1075d26238", + "title": "feat: custom cz plugins now support bumping version", + "body": "", + }, + { + "rev": "ad17acff2e3a2e141cbc3c6efd7705e4e6de9bfc", + "title": "docs: added bump gif", + "body": "", + }, + { + "rev": "56c8a8da84e42b526bcbe130bd194306f7c7e813", + "title": "bump: version 1.1.0 → 1.1.1", + "body": "", + }, + { + "rev": "74c6134b1b2e6bb8b07ed53410faabe99b204f36", + "title": "refactor: changed stdout statements", + "body": "", + }, + { + "rev": "cbc7b5f22c4e74deff4bc92d14e19bd93524711e", + "title": "fix(bump): commit message now fits better with semver", + "body": "", + }, + { + "rev": "1ba46f2a63cb9d6e7472eaece21528c8cd28b118", + "title": "fix: conventional commit 'breaking change' in body instead of title", + "body": "closes #16", + }, + { + "rev": "c35dbffd1bb98bb0b3d1593797e79d1c3366af8f", + "title": "refactor(schema): command logic removed from commitizen base", + "body": "", + }, + { + "rev": "25313397a4ac3dc5b5c986017bee2a614399509d", + "title": "refactor(info): command logic removed from commitizen base", + "body": "", + }, + { + "rev": "d2f13ac41b4e48995b3b619d931c82451886e6ff", + "title": "refactor(example): command logic removed from commitizen base", + "body": "", + }, + { + "rev": "d839e317e5b26671b010584ad8cc6bf362400fa1", + "title": "refactor(commit): moved most of the commit logic to the commit command", + "body": "", + }, + { + "rev": "12d0e65beda969f7983c444ceedc2a01584f4e08", + "title": "docs(README): updated documentation url)", + "body": "", + }, + { + "rev": "fb4c85abe51c228e50773e424cbd885a8b6c610d", + "title": "docs: mkdocs documentation", + "body": "", + }, + { + "rev": "17efb44d2cd16f6621413691a543e467c7d2dda6", + "title": "Bump version 1.0.0 → 1.1.0", + "body": "", + }, + { + "rev": "6012d9eecfce8163d75c8fff179788e9ad5347da", + "title": "test: fixed issues with conf", + "body": "", + }, + { + "rev": "0c7fb0ca0168864dfc55d83c210da57771a18319", + "title": "docs(README): some new information about bump", + "body": "", + }, + { + "rev": "cb1dd2019d522644da5bdc2594dd6dee17122d7f", + "title": "feat: new working bump command", + "body": "", + }, + { + "rev": "9c7450f85df6bf6be508e79abf00855a30c3c73c", + "title": "feat: create version tag", + "body": "", + }, + { + "rev": "9f3af3772baab167e3fd8775d37f041440184251", + "title": "docs: added new changelog", + "body": "", + }, + { + "rev": "b0d6a3defbfde14e676e7eb34946409297d0221b", + "title": "feat: update given files with new version", + "body": "", + }, + { + "rev": "d630d07d912e420f0880551f3ac94e933f9d3beb", + "title": "fix: removed all from commit", + "body": "", + }, + { + "rev": "1792b8980c58787906dbe6836f93f31971b1ec2d", + "title": "feat(config): new set key, used to set version to cfg", + "body": "", + }, + { + "rev": "52def1ea3555185ba4b936b463311949907e31ec", + "title": "feat: support for pyproject.toml", + "body": "", + }, + { + "rev": "3127e05077288a5e2b62893345590bf1096141b7", + "title": "feat: first semantic version bump implementaiton", + "body": "", + }, + { + "rev": "fd480ed90a80a6ffa540549408403d5b60d0e90c", + "title": "fix: fix config file not working", + "body": "", + }, + { + "rev": "e4840a059731c0bf488381ffc77e989e85dd81ad", + "title": "refactor: added commands folder, better integration with decli", + "body": "", + }, + { + "rev": "aa44a92d68014d0da98965c0c2cb8c07957d4362", + "title": "Bump version: 1.0.0b2 → 1.0.0", + "body": "", + }, + { + "rev": "58bb709765380dbd46b74ce6e8978515764eb955", + "title": "docs(README): new badges", + "body": "", + }, + { + "rev": "97afb0bb48e72b6feca793091a8a23c706693257", + "title": "Merge pull request #10 from Woile/feat/decli", + "body": "Feat/decli", + }, + { + "rev": "9cecb9224aa7fa68d4afeac37eba2a25770ef251", + "title": "style: black to files", + "body": "", + }, + { + "rev": "f5781d1a2954d71c14ade2a6a1a95b91310b2577", + "title": "ci: added travis", + "body": "", + }, + { + "rev": "80105fb3c6d45369bc0cbf787bd329fba603864c", + "title": "refactor: removed delegator, added decli and many tests", + "body": "BREAKING CHANGE: API is stable", + }, + { + "rev": "a96008496ffefb6b1dd9b251cb479eac6a0487f7", + "title": "docs: updated test command", + "body": "", + }, + { + "rev": "aab33d13110f26604fb786878856ec0b9e5fc32b", + "title": "Bump version: 1.0.0b1 → 1.0.0b2", + "body": "", + }, + { + "rev": "b73791563d2f218806786090fb49ef70faa51a3a", + "title": "docs(README): updated to reflect current state", + "body": "", + }, + { + "rev": "7aa06a454fb717408b3657faa590731fb4ab3719", + "title": "Merge pull request #9 from Woile/dev", + "body": "feat: py3 only, tests and conventional commits 1.0", + }, + { + "rev": "7c7e96b723c2aaa1aec3a52561f680adf0b60e97", + "title": "Bump version: 0.9.11 → 1.0.0b1", + "body": "", + }, + { + "rev": "ed830019581c83ba633bfd734720e6758eca6061", + "title": "feat: py3 only, tests and conventional commits 1.0", + "body": "more tests\npyproject instead of Pipfile\nquestionary instead of whaaaaat (promptkit 2.0.0 support)", + }, + { + "rev": "c52eca6f74f844ab3ffbde61d98ef96071e132b7", + "title": "Bump version: 0.9.10 → 0.9.11", + "body": "", + }, + { + "rev": "0326652b2657083929507ee66d4d1a0899e861ba", + "title": "fix(config): load config reads in order without failing if there is no commitizen section", + "body": "Closes #8", + }, + { + "rev": "b3f89892222340150e32631ae6b7aab65230036f", + "title": "Bump version: 0.9.9 → 0.9.10", + "body": "", + }, + { + "rev": "5e837bf8ef0735193597372cd2d85e31a8f715b9", + "title": "fix: parse scope (this is my punishment for not having tests)", + "body": "", + }, + { + "rev": "684e0259cc95c7c5e94854608cd3dcebbd53219e", + "title": "Bump version: 0.9.8 → 0.9.9", + "body": "", + }, + { + "rev": "ca38eac6ff09870851b5c76a6ff0a2a8e5ecda15", + "title": "fix: parse scope empty", + "body": "", + }, + { + "rev": "64168f18d4628718c49689ee16430549e96c5d4b", + "title": "Bump version: 0.9.7 → 0.9.8", + "body": "", + }, + { + "rev": "9d4def716ef235a1fa5ae61614366423fbc8256f", + "title": "fix(scope): parse correctly again", + "body": "", + }, + { + "rev": "33b0bf1a0a4dc60aac45ed47476d2e5473add09e", + "title": "Bump version: 0.9.6 → 0.9.7", + "body": "", + }, + { + "rev": "696885e891ec35775daeb5fec3ba2ab92c2629e1", + "title": "fix(scope): parse correctly", + "body": "", + }, + { + "rev": "bef4a86761a3bda309c962bae5d22ce9b57119e4", + "title": "Bump version: 0.9.5 → 0.9.6", + "body": "", + }, + { + "rev": "72472efb80f08ee3fd844660afa012c8cb256e4b", + "title": "refactor(conventionalCommit): moved fitlers to questions instead of message", + "body": "", + }, + { + "rev": "b5561ce0ab3b56bb87712c8f90bcf37cf2474f1b", + "title": "fix(manifest): inluded missing files", + "body": "", + }, + { + "rev": "3e31714dc737029d96898f412e4ecd2be1bcd0ce", + "title": "Bump version: 0.9.4 → 0.9.5", + "body": "", + }, + { + "rev": "9df721e06595fdd216884c36a28770438b4f4a39", + "title": "fix(config): home path for python versions between 3.0 and 3.5", + "body": "", + }, + { + "rev": "0cf6ada372470c8d09e6c9e68ebf94bbd5a1656f", + "title": "Bump version: 0.9.3 → 0.9.4", + "body": "", + }, + { + "rev": "973c6b3e100f6f69a3fe48bd8ee55c135b96c318", + "title": "feat(cli): added version", + "body": "", + }, + { + "rev": "dacc86159b260ee98eb5f57941c99ba731a01399", + "title": "Bump version: 0.9.2 → 0.9.3", + "body": "", + }, + { + "rev": "4368f3c3cbfd4a1ced339212230d854bc5bab496", + "title": "feat(commiter): conventional commit is a bit more intelligent now", + "body": "", + }, + { + "rev": "da94133288727d35dae9b91866a25045038f2d38", + "title": "docs(README): motivation", + "body": "", + }, + { + "rev": "1541f54503d2e1cf39bd777c0ca5ab5eb78772ba", + "title": "Bump version: 0.9.1 → 0.9.2", + "body": "", + }, + { + "rev": "ddc855a637b7879108308b8dbd85a0fd27c7e0e7", + "title": "refactor: renamed conventional_changelog to conventional_commits, not backward compatible", + "body": "", + }, + { + "rev": "46e9032e18a819e466618c7a014bcb0e9981af9e", + "title": "Bump version: 0.9.0 → 0.9.1", + "body": "", + }, + { + "rev": "0fef73cd7dc77a25b82e197e7c1d3144a58c1350", + "title": "fix(setup.py): future is now required for every python version", + "body": "", + }, ] -CHANGELOG_TEMPLATE = """ -## 1.0.0 (2019-07-12) - -### Bug fixes - -- issue in poetry add preventing the installation in py36 -- **users**: lorem ipsum apap - - -### Features - -- it is possible to specify a pattern to be matched in configuration files bump. - -## 0.9 (2019-07-11) - -### Bug fixes - -- holis - -""" - - -@pytest.fixture -def existing_changelog_file(request): - changelog_path = "tests/CHANGELOG.md" - - with open(changelog_path, "w") as f: - f.write(CHANGELOG_TEMPLATE) - - yield changelog_path - - os.remove(changelog_path) - - -def test_read_changelog_blocks(existing_changelog_file): - blocks = changelog.find_version_blocks(existing_changelog_file) - blocks = list(blocks) - amount_of_blocks = len(blocks) - assert amount_of_blocks == 2 - -VERSION_CASES: list = [ - ("## 1.0.0 (2019-07-12)", {"version": "1.0.0", "date": "2019-07-12"}), - ("## 2.3.0a0", {"version": "2.3.0a0", "date": None}), - ("## 0.10.0a0", {"version": "0.10.0a0", "date": None}), - ("## 1.0.0rc0", {"version": "1.0.0rc0", "date": None}), - ("## 1beta", {"version": "1beta", "date": None}), - ( - "## 1.0.0rc1+e20d7b57f3eb (2019-3-24)", - {"version": "1.0.0rc1+e20d7b57f3eb", "date": "2019-3-24"}, - ), - ("### Bug fixes", {}), - ("- issue in poetry add preventing the installation in py36", {}), +TAGS = [ + ("v1.2.0", "141ee441c9c9da0809c554103a558eb17c30ed17", "2019-04-19"), + ("v1.1.1", "56c8a8da84e42b526bcbe130bd194306f7c7e813", "2019-04-18"), + ("v1.1.0", "17efb44d2cd16f6621413691a543e467c7d2dda6", "2019-04-14"), + ("v1.0.0", "aa44a92d68014d0da98965c0c2cb8c07957d4362", "2019-03-01"), + ("1.0.0b2", "aab33d13110f26604fb786878856ec0b9e5fc32b", "2019-01-18"), + ("v1.0.0b1", "7c7e96b723c2aaa1aec3a52561f680adf0b60e97", "2019-01-17"), + ("v0.9.11", "c52eca6f74f844ab3ffbde61d98ef96071e132b7", "2018-12-17"), + ("v0.9.10", "b3f89892222340150e32631ae6b7aab65230036f", "2018-09-22"), + ("v0.9.9", "684e0259cc95c7c5e94854608cd3dcebbd53219e", "2018-09-22"), + ("v0.9.8", "64168f18d4628718c49689ee16430549e96c5d4b", "2018-09-22"), + ("v0.9.7", "33b0bf1a0a4dc60aac45ed47476d2e5473add09e", "2018-09-22"), + ("v0.9.6", "bef4a86761a3bda309c962bae5d22ce9b57119e4", "2018-09-19"), + ("v0.9.5", "3e31714dc737029d96898f412e4ecd2be1bcd0ce", "2018-08-24"), + ("v0.9.4", "0cf6ada372470c8d09e6c9e68ebf94bbd5a1656f", "2018-08-02"), + ("v0.9.3", "dacc86159b260ee98eb5f57941c99ba731a01399", "2018-07-28"), + ("v0.9.2", "1541f54503d2e1cf39bd777c0ca5ab5eb78772ba", "2017-11-11"), + ("v0.9.1", "46e9032e18a819e466618c7a014bcb0e9981af9e", "2017-11-11"), ] -CATEGORIES_CASES: list = [ - ("## 1.0.0 (2019-07-12)", {}), - ("## 2.3.0a0", {}), - ("### Bug fixes", {"change_type": "Bug fixes"}), - ("### Features", {"change_type": "Features"}), - ("- issue in poetry add preventing the installation in py36", {}), -] -CATEGORIES_TRANSFORMATIONS: list = [ - ("Bug fixes", "fix"), - ("Features", "feat"), - ("BREAKING CHANGES", "BREAKING CHANGES"), -] - -MESSAGES_CASES: list = [ - ("## 1.0.0 (2019-07-12)", {}), - ("## 2.3.0a0", {}), - ("### Bug fixes", {}), - ( - "- name no longer accept invalid chars", - {"message": "name no longer accept invalid chars", "scope": None}, - ), - ( - "- **users**: lorem ipsum apap", - {"message": "lorem ipsum apap", "scope": "users"}, - ), -] +@pytest.fixture # type: ignore +def gitcommits() -> list: + commits = [ + git.GitCommit(commit["rev"], commit["title"], commit["body"]) + for commit in COMMITS_DATA + ] + return commits -@pytest.mark.parametrize("test_input,expected", VERSION_CASES) -def test_parse_md_version(test_input, expected): - assert changelog.parse_md_version(test_input) == expected +@pytest.fixture # type: ignore +def tags() -> list: + tags = [git.GitTag(*tag) for tag in TAGS] + return tags -@pytest.mark.parametrize("test_input,expected", CATEGORIES_CASES) -def test_parse_md_change_type(test_input, expected): - assert changelog.parse_md_change_type(test_input) == expected +@pytest.fixture # type: ignore +def changelog_content() -> str: + changelog_path = "tests/CHANGELOG_FOR_TEST.md" + with open(changelog_path, "r") as f: + return f.read() -@pytest.mark.parametrize("test_input,expected", CATEGORIES_TRANSFORMATIONS) -def test_transform_change_type(test_input, expected): - assert changelog.transform_change_type(test_input) == expected +def test_get_commit_tag_is_a_version(gitcommits, tags): + commit = gitcommits[0] + tag = git.GitTag(*TAGS[0]) + current_key = changelog.get_commit_tag(commit, tags) + assert current_key == tag -@pytest.mark.parametrize("test_input,expected", MESSAGES_CASES) -def test_parse_md_message(test_input, expected): - assert changelog.parse_md_message(test_input) == expected +def test_get_commit_tag_is_None(gitcommits, tags): + commit = gitcommits[1] + current_key = changelog.get_commit_tag(commit, tags) + assert current_key is None -def test_transform_change_type_fail(): - with pytest.raises(ValueError) as excinfo: - changelog.transform_change_type("Bugs") - assert "Could not match a change_type" in str(excinfo.value) +def test_generate_tree_from_commits(gitcommits, tags): + parser = defaults.commit_parser + changelog_pattern = defaults.bump_pattern + tree = changelog.generate_tree_from_commits( + gitcommits, tags, parser, changelog_pattern + ) -def test_generate_block_tree(existing_changelog_file): - blocks = changelog.find_version_blocks(existing_changelog_file) - block = next(blocks) - tree = changelog.generate_block_tree(block) - assert tree == { - "commits": [ - { - "scope": None, - "message": "issue in poetry add preventing the installation in py36", - "change_type": "fix", + assert tuple(tree) == ( + { + "version": "v1.2.0", + "date": "2019-04-19", + "changes": { + "feat": [ + { + "scope": None, + "breaking": None, + "message": "custom cz plugins now support bumping version", + } + ] }, - {"scope": "users", "message": "lorem ipsum apap", "change_type": "fix"}, - { - "scope": None, - "message": ( - "it is possible to specify a pattern to be matched " - "in configuration files bump." - ), - "change_type": "feat", + }, + { + "version": "v1.1.1", + "date": "2019-04-18", + "changes": { + "refactor": [ + { + "scope": None, + "breaking": None, + "message": "changed stdout statements", + }, + { + "scope": "schema", + "breaking": None, + "message": "command logic removed from commitizen base", + }, + { + "scope": "info", + "breaking": None, + "message": "command logic removed from commitizen base", + }, + { + "scope": "example", + "breaking": None, + "message": "command logic removed from commitizen base", + }, + { + "scope": "commit", + "breaking": None, + "message": "moved most of the commit logic to the commit command", + }, + ], + "fix": [ + { + "scope": "bump", + "breaking": None, + "message": "commit message now fits better with semver", + }, + { + "scope": None, + "breaking": None, + "message": "conventional commit 'breaking change' in body instead of title", + }, + ], }, - ], - "version": "1.0.0", - "date": "2019-07-12", - } - - -def test_generate_full_tree(existing_changelog_file): - blocks = changelog.find_version_blocks(existing_changelog_file) - tree = list(changelog.generate_full_tree(blocks)) - - assert tree == [ + }, + { + "version": "v1.1.0", + "date": "2019-04-14", + "changes": { + "feat": [ + { + "scope": None, + "breaking": None, + "message": "new working bump command", + }, + {"scope": None, "breaking": None, "message": "create version tag"}, + { + "scope": None, + "breaking": None, + "message": "update given files with new version", + }, + { + "scope": "config", + "breaking": None, + "message": "new set key, used to set version to cfg", + }, + { + "scope": None, + "breaking": None, + "message": "support for pyproject.toml", + }, + { + "scope": None, + "breaking": None, + "message": "first semantic version bump implementaiton", + }, + ], + "fix": [ + { + "scope": None, + "breaking": None, + "message": "removed all from commit", + }, + { + "scope": None, + "breaking": None, + "message": "fix config file not working", + }, + ], + "refactor": [ + { + "scope": None, + "breaking": None, + "message": "added commands folder, better integration with decli", + } + ], + }, + }, + { + "version": "v1.0.0", + "date": "2019-03-01", + "changes": { + "refactor": [ + { + "scope": None, + "breaking": None, + "message": "removed delegator, added decli and many tests", + } + ], + "BREAKING CHANGE": [ + {"scope": None, "breaking": None, "message": "API is stable"} + ], + }, + }, + {"version": "1.0.0b2", "date": "2019-01-18", "changes": {}}, + { + "version": "v1.0.0b1", + "date": "2019-01-17", + "changes": { + "feat": [ + { + "scope": None, + "breaking": None, + "message": "py3 only, tests and conventional commits 1.0", + } + ] + }, + }, + { + "version": "v0.9.11", + "date": "2018-12-17", + "changes": { + "fix": [ + { + "scope": "config", + "breaking": None, + "message": "load config reads in order without failing if there is no commitizen section", + } + ] + }, + }, + { + "version": "v0.9.10", + "date": "2018-09-22", + "changes": { + "fix": [ + { + "scope": None, + "breaking": None, + "message": "parse scope (this is my punishment for not having tests)", + } + ] + }, + }, { - "commits": [ - { - "scope": None, - "message": ( - "issue in poetry add preventing the installation in py36" - ), - "change_type": "fix", - }, - {"scope": "users", "message": "lorem ipsum apap", "change_type": "fix"}, - { - "scope": None, - "message": ( - "it is possible to specify a pattern to be matched " - "in configuration files bump." - ), - "change_type": "feat", - }, - ], - "version": "1.0.0", - "date": "2019-07-12", + "version": "v0.9.9", + "date": "2018-09-22", + "changes": { + "fix": [ + {"scope": None, "breaking": None, "message": "parse scope empty"} + ] + }, + }, + { + "version": "v0.9.8", + "date": "2018-09-22", + "changes": { + "fix": [ + { + "scope": "scope", + "breaking": None, + "message": "parse correctly again", + } + ] + }, }, { - "commits": [{"scope": None, "message": "holis", "change_type": "fix"}], - "version": "0.9", - "date": "2019-07-11", + "version": "v0.9.7", + "date": "2018-09-22", + "changes": { + "fix": [ + {"scope": "scope", "breaking": None, "message": "parse correctly"} + ] + }, + }, + { + "version": "v0.9.6", + "date": "2018-09-19", + "changes": { + "refactor": [ + { + "scope": "conventionalCommit", + "breaking": None, + "message": "moved fitlers to questions instead of message", + } + ], + "fix": [ + { + "scope": "manifest", + "breaking": None, + "message": "inluded missing files", + } + ], + }, }, + { + "version": "v0.9.5", + "date": "2018-08-24", + "changes": { + "fix": [ + { + "scope": "config", + "breaking": None, + "message": "home path for python versions between 3.0 and 3.5", + } + ] + }, + }, + { + "version": "v0.9.4", + "date": "2018-08-02", + "changes": { + "feat": [{"scope": "cli", "breaking": None, "message": "added version"}] + }, + }, + { + "version": "v0.9.3", + "date": "2018-07-28", + "changes": { + "feat": [ + { + "scope": "commiter", + "breaking": None, + "message": "conventional commit is a bit more intelligent now", + } + ] + }, + }, + { + "version": "v0.9.2", + "date": "2017-11-11", + "changes": { + "refactor": [ + { + "scope": None, + "breaking": None, + "message": "renamed conventional_changelog to conventional_commits, not backward compatible", + } + ] + }, + }, + { + "version": "v0.9.1", + "date": "2017-11-11", + "changes": { + "fix": [ + { + "scope": "setup.py", + "breaking": None, + "message": "future is now required for every python version", + } + ] + }, + }, + ) + + +def test_render_changelog(gitcommits, tags, changelog_content): + parser = defaults.commit_parser + changelog_pattern = defaults.bump_pattern + tree = changelog.generate_tree_from_commits( + gitcommits, tags, parser, changelog_pattern + ) + result = changelog.render_changelog(tree) + assert result == changelog_content + + +def test_render_changelog_unreleased(gitcommits): + some_commits = gitcommits[:7] + parser = defaults.commit_parser + changelog_pattern = defaults.bump_pattern + tree = changelog.generate_tree_from_commits( + some_commits, [], parser, changelog_pattern + ) + result = changelog.render_changelog(tree) + assert "Unreleased" in result + + +def test_render_changelog_tag_and_unreleased(gitcommits, tags): + some_commits = gitcommits[:7] + single_tag = [ + tag for tag in tags if tag.rev == "56c8a8da84e42b526bcbe130bd194306f7c7e813" ] + + parser = defaults.commit_parser + changelog_pattern = defaults.bump_pattern + tree = changelog.generate_tree_from_commits( + some_commits, single_tag, parser, changelog_pattern + ) + result = changelog.render_changelog(tree) + + assert "Unreleased" in result + assert "## v1.1.1" in result diff --git a/tests/test_changelog_parser.py b/tests/test_changelog_parser.py new file mode 100644 index 0000000000..352447ae26 --- /dev/null +++ b/tests/test_changelog_parser.py @@ -0,0 +1,194 @@ +import os + +import pytest + +from commitizen import changelog_parser + +CHANGELOG_TEMPLATE = """ +## 1.0.0 (2019-07-12) + +### Fix + +- issue in poetry add preventing the installation in py36 +- **users**: lorem ipsum apap + +### Feat + +- it is possible to specify a pattern to be matched in configuration files bump. + +## 0.9 (2019-07-11) + +### Fix + +- holis + +""" + + +@pytest.fixture # type: ignore +def changelog_content() -> str: + changelog_path = "tests/CHANGELOG_FOR_TEST.md" + with open(changelog_path, "r") as f: + return f.read() + + +@pytest.fixture +def existing_changelog_file(request): + changelog_path = "tests/CHANGELOG.md" + + with open(changelog_path, "w") as f: + f.write(CHANGELOG_TEMPLATE) + + yield changelog_path + + os.remove(changelog_path) + + +def test_read_changelog_blocks(existing_changelog_file): + blocks = changelog_parser.find_version_blocks(existing_changelog_file) + blocks = list(blocks) + amount_of_blocks = len(blocks) + assert amount_of_blocks == 2 + + +VERSION_CASES: list = [ + ("## 1.0.0 (2019-07-12)", {"version": "1.0.0", "date": "2019-07-12"}), + ("## 2.3.0a0", {"version": "2.3.0a0", "date": None}), + ("## 0.10.0a0", {"version": "0.10.0a0", "date": None}), + ("## 1.0.0rc0", {"version": "1.0.0rc0", "date": None}), + ("## 1beta", {"version": "1beta", "date": None}), + ( + "## 1.0.0rc1+e20d7b57f3eb (2019-3-24)", + {"version": "1.0.0rc1+e20d7b57f3eb", "date": "2019-3-24"}, + ), + ("### Bug fixes", {}), + ("- issue in poetry add preventing the installation in py36", {}), +] + +CATEGORIES_CASES: list = [ + ("## 1.0.0 (2019-07-12)", {}), + ("## 2.3.0a0", {}), + ("### Bug fixes", {"change_type": "Bug fixes"}), + ("### Features", {"change_type": "Features"}), + ("- issue in poetry add preventing the installation in py36", {}), +] + +CATEGORIES_TRANSFORMATIONS: list = [ + ("Bug fixes", "fix"), + ("Features", "feat"), + ("BREAKING CHANGES", "BREAKING CHANGES"), +] + +MESSAGES_CASES: list = [ + ("## 1.0.0 (2019-07-12)", {}), + ("## 2.3.0a0", {}), + ("### Fix", {}), + ( + "- name no longer accept invalid chars", + { + "message": "name no longer accept invalid chars", + "scope": None, + "breaking": None, + }, + ), + ( + "- **users**: lorem ipsum apap", + {"message": "lorem ipsum apap", "scope": "users", "breaking": None}, + ), +] + + +@pytest.mark.parametrize("test_input,expected", VERSION_CASES) +def test_parse_md_version(test_input, expected): + assert changelog_parser.parse_md_version(test_input) == expected + + +@pytest.mark.parametrize("test_input,expected", CATEGORIES_CASES) +def test_parse_md_change_type(test_input, expected): + assert changelog_parser.parse_md_change_type(test_input) == expected + + +@pytest.mark.parametrize("test_input,expected", CATEGORIES_TRANSFORMATIONS) +def test_transform_change_type(test_input, expected): + assert changelog_parser.transform_change_type(test_input) == expected + + +@pytest.mark.parametrize("test_input,expected", MESSAGES_CASES) +def test_parse_md_message(test_input, expected): + assert changelog_parser.parse_md_message(test_input) == expected + + +def test_transform_change_type_fail(): + with pytest.raises(ValueError) as excinfo: + changelog_parser.transform_change_type("Bugs") + assert "Could not match a change_type" in str(excinfo.value) + + +def test_generate_block_tree(existing_changelog_file): + blocks = changelog_parser.find_version_blocks(existing_changelog_file) + block = next(blocks) + tree = changelog_parser.generate_block_tree(block) + assert tree == { + "changes": { + "fix": [ + { + "scope": None, + "breaking": None, + "message": "issue in poetry add preventing the installation in py36", + }, + {"scope": "users", "breaking": None, "message": "lorem ipsum apap"}, + ], + "feat": [ + { + "scope": None, + "breaking": None, + "message": ( + "it is possible to specify a pattern to be matched " + "in configuration files bump." + ), + } + ], + }, + "version": "1.0.0", + "date": "2019-07-12", + } + + +def test_generate_full_tree(existing_changelog_file): + blocks = changelog_parser.find_version_blocks(existing_changelog_file) + tree = list(changelog_parser.generate_full_tree(blocks)) + + assert tree == [ + { + "changes": { + "fix": [ + { + "scope": None, + "message": "issue in poetry add preventing the installation in py36", + "breaking": None, + }, + { + "scope": "users", + "message": "lorem ipsum apap", + "breaking": None, + }, + ], + "feat": [ + { + "scope": None, + "message": "it is possible to specify a pattern to be matched in configuration files bump.", + "breaking": None, + }, + ], + }, + "version": "1.0.0", + "date": "2019-07-12", + }, + { + "changes": { + "fix": [{"scope": None, "message": "holis", "breaking": None}], + }, + "version": "0.9", + "date": "2019-07-11", + }, + ] From 84471b4e8b767e89cbe4a5e29181d47e882e4377 Mon Sep 17 00:00:00 2001 From: santiago fraire Date: Mon, 27 Apr 2020 12:06:09 +0200 Subject: [PATCH 083/427] feat(changelog): add incremental flag --- commitizen/changelog.py | 130 +++++++++++++-- commitizen/cli.py | 21 ++- commitizen/commands/bump.py | 13 ++ commitizen/commands/changelog.py | 121 ++++++++------ commitizen/commands/init.py | 4 +- commitizen/defaults.py | 1 + commitizen/error_codes.py | 3 + commitizen/git.py | 2 + docs/changelog.md | 17 +- pyproject.toml | 1 + tests/commands/test_changelog_command.py | 203 ++++++++++++++++++++--- tests/test_changelog_meta.py | 165 ++++++++++++++++++ tests/test_changelog_parser.py | 2 +- 13 files changed, 591 insertions(+), 92 deletions(-) create mode 100644 tests/test_changelog_meta.py diff --git a/commitizen/changelog.py b/commitizen/changelog.py index 25d090b7dd..9596dcb027 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -18,8 +18,12 @@ 7. generate changelog Extra: -- Generate full or partial changelog -- Include in tree from file all the extra comments added manually +- [x] Generate full or partial changelog +- [x] Include in tree from file all the extra comments added manually +- [ ] Add unreleased value +- [ ] hook after message is parsed (add extra information like hyperlinks) +- [ ] hook after changelog is generated (api calls) +- [ ] add support for change_type maps """ import re from collections import defaultdict @@ -29,7 +33,7 @@ from jinja2 import Template from commitizen import defaults -from commitizen.git import GitCommit, GitProtocol, GitTag +from commitizen.git import GitCommit, GitTag CATEGORIES = [ ("fix", "fix"), @@ -55,15 +59,9 @@ def transform_change_type(change_type: str) -> str: raise ValueError(f"Could not match a change_type with {change_type}") -def get_commit_tag(commit: GitProtocol, tags: List[GitProtocol]) -> Optional[GitTag]: +def get_commit_tag(commit: GitCommit, tags: List[GitTag]) -> Optional[GitTag]: """""" - try: - tag_index = tags.index(commit) - except ValueError: - return None - else: - tag = tags[tag_index] - return tag + return next((tag for tag in tags if tag.rev == commit.rev), None) def generate_tree_from_commits( @@ -71,6 +69,7 @@ def generate_tree_from_commits( tags: List[GitTag], commit_parser: str, changelog_pattern: str = defaults.bump_pattern, + unreleased_version: Optional[str] = None, ) -> Iterable[Dict]: pat = re.compile(changelog_pattern) map_pat = re.compile(commit_parser) @@ -78,7 +77,7 @@ def generate_tree_from_commits( latest_commit = commits[0] current_tag: Optional[GitTag] = get_commit_tag(latest_commit, tags) - current_tag_name: str = "Unreleased" + current_tag_name: str = unreleased_version or "Unreleased" current_tag_date: str = "" if current_tag is not None and current_tag.name: current_tag_name = current_tag.name @@ -109,6 +108,7 @@ def generate_tree_from_commits( message = map_pat.match(commit.message) message_body = map_pat.match(commit.body) if message: + # TODO: add a post hook coming from a rule (CzBase) parsed_message: Dict = message.groupdict() # change_type becomes optional by providing None change_type = parsed_message.pop("change_type", None) @@ -132,3 +132,109 @@ def render_changelog(tree: Iterable) -> str: jinja_template = Template(template_file, trim_blocks=True) changelog: str = jinja_template.render(tree=tree) return changelog + + +def parse_version_from_markdown(value: str) -> Optional[str]: + if not value.startswith("#"): + return None + m = re.search(defaults.version_parser, value) + if not m: + return None + return m.groupdict().get("version") + + +def parse_title_type_of_line(value: str) -> Optional[str]: + md_title_parser = r"^(?P#+)" + m = re.search(md_title_parser, value) + if not m: + return None + return m.groupdict().get("title") + + +def get_metadata(filepath: str) -> Dict: + unreleased_start: Optional[int] = None + unreleased_end: Optional[int] = None + unreleased_title: Optional[str] = None + latest_version: Optional[str] = None + latest_version_position: Optional[int] = None + with open(filepath, "r") as changelog_file: + for index, line in enumerate(changelog_file): + line = line.strip().lower() + + unreleased: Optional[str] = None + if "unreleased" in line: + unreleased = parse_title_type_of_line(line) + # Try to find beginning and end lines of the unreleased block + if unreleased: + unreleased_start = index + unreleased_title = unreleased + continue + elif ( + isinstance(unreleased_title, str) + and parse_title_type_of_line(line) == unreleased_title + ): + unreleased_end = index + + # Try to find the latest release done + version = parse_version_from_markdown(line) + if version: + latest_version = version + latest_version_position = index + break # there's no need for more info + if unreleased_start is not None and unreleased_end is None: + unreleased_end = index + return { + "unreleased_start": unreleased_start, + "unreleased_end": unreleased_end, + "latest_version": latest_version, + "latest_version_position": latest_version_position, + } + + +def incremental_build(new_content: str, lines: List, metadata: Dict) -> List: + """Takes the original lines and updates with new_content. + + The metadata holds information enough to remove the old unreleased and + where to place the new content + + Arguments: + lines -- the lines from the changelog + new_content -- this should be placed somewhere in the lines + metadata -- information about the changelog + + Returns: + List -- updated lines + """ + unreleased_start = metadata.get("unreleased_start") + unreleased_end = metadata.get("unreleased_end") + latest_version_position = metadata.get("latest_version_position") + skip = False + output_lines: List = [] + for index, line in enumerate(lines): + if index == unreleased_start: + skip = True + elif index == unreleased_end: + skip = False + if ( + latest_version_position is None + or isinstance(latest_version_position, int) + and isinstance(unreleased_end, int) + and latest_version_position > unreleased_end + ): + continue + + if skip: + continue + + if ( + isinstance(latest_version_position, int) + and index == latest_version_position + ): + + output_lines.append(new_content) + output_lines.append("\n") + + output_lines.append(line) + if not isinstance(latest_version_position, int): + output_lines.append(new_content) + return output_lines diff --git a/commitizen/cli.py b/commitizen/cli.py index 94eb2ca845..f5b41a2e2f 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -86,6 +86,12 @@ "action": "store_true", "help": "bump version in the files from the config", }, + { + "name": ["--changelog", "-ch"], + "action": "store_true", + "default": False, + "help": "generate the changelog for the newest version", + }, { "name": "--yes", "action": "store_true", @@ -131,6 +137,17 @@ "default": False, "help": "show changelog to stdout", }, + { + "name": "--file-name", + "help": "file name of changelog (default: 'CHANGELOG.md')", + }, + { + "name": "--unreleased-version", + "help": ( + "set the value for the new version (use the tag value), " + "instead of using unreleased" + ), + }, { "name": "--incremental", "action": "store_true", @@ -140,10 +157,6 @@ "useful if the changelog has been manually modified" ), }, - { - "name": "--file-name", - "help": "file name of changelog (default: 'CHANGELOG.md')", - }, { "name": "--start-rev", "default": None, diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 90ec715744..1d0439e4b9 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -4,6 +4,7 @@ from packaging.version import Version from commitizen import bump, factory, git, out +from commitizen.commands.changelog import Changelog from commitizen.config import BaseConfig from commitizen.error_codes import ( COMMIT_FAILED, @@ -29,6 +30,7 @@ def __init__(self, config: BaseConfig, arguments: dict): }, } self.cz = factory.commiter_factory(self.config) + self.changelog = arguments["changelog"] def is_initial_tag(self, current_tag_version: str, is_yes: bool = False) -> bool: """Check if reading the whole git tree up to HEAD is needed.""" @@ -131,6 +133,17 @@ def __call__(self): # noqa: C901 if is_files_only: raise SystemExit() + if self.changelog: + changelog = Changelog( + self.config, + { + "unreleased_version": new_tag_version, + "incremental": True, + "dry_run": dry_run, + }, + ) + changelog() + self.config.set_key("version", new_version.public) c = git.commit(message, args="-a") if c.err: diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 016c320a31..12f43f775d 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -1,12 +1,16 @@ -import re -from collections import OrderedDict - -import pkg_resources -from jinja2 import Template +import os.path +from difflib import SequenceMatcher +from operator import itemgetter +from typing import Dict, List from commitizen import changelog, factory, git, out from commitizen.config import BaseConfig -from commitizen.error_codes import NO_COMMITS_FOUND, NO_PATTERN_MAP, TAG_FAILED +from commitizen.error_codes import NO_COMMITS_FOUND, NO_PATTERN_MAP, NO_REVISION +from commitizen.git import GitTag + + +def similar(a, b): + return SequenceMatcher(None, a, b).ratio() class Changelog: @@ -16,74 +20,87 @@ def __init__(self, config: BaseConfig, args): self.config: BaseConfig = config self.cz = factory.commiter_factory(self.config) - self.file_name = args["file_name"] or self.config.settings.get("changelog_file") + self.start_rev = args.get("start_rev") + self.file_name = args.get("file_name") or self.config.settings.get( + "changelog_file" + ) self.incremental = args["incremental"] self.dry_run = args["dry_run"] - self.start_rev = args["start_rev"] + self.unreleased_version = args["unreleased_version"] + + def _find_incremental_rev(self, latest_version: str, tags: List[GitTag]) -> str: + """Try to find the 'start_rev'. + + We use a similarity approach. We know how to parse the version from the markdown + changelog, but not the whole tag, we don't even know how's the tag made. + + This 'smart' function tries to find a similarity between the found version number + and the available tag. + + The SIMILARITY_THRESHOLD is an empirical value, it may have to be adjusted based + on our experience. + """ + SIMILARITY_THRESHOLD = 0.89 + tag_ratio = map( + lambda tag: (SequenceMatcher(None, latest_version, tag.name).ratio(), tag), + tags, + ) + try: + score, tag = max(tag_ratio, key=itemgetter(0)) + except ValueError: + raise SystemExit(NO_REVISION) + if score < SIMILARITY_THRESHOLD: + raise SystemExit(NO_REVISION) + start_rev = tag.name + return start_rev def __call__(self): - # changelog_map = self.cz.changelog_map commit_parser = self.cz.commit_parser changelog_pattern = self.cz.changelog_pattern + start_rev = self.start_rev + unreleased_version = self.unreleased_version + changelog_meta: Dict = {} if not changelog_pattern or not commit_parser: out.error( f"'{self.config.settings['name']}' rule does not support changelog" ) raise SystemExit(NO_PATTERN_MAP) - # pat = re.compile(changelog_pattern) - - commits = git.get_commits(start=self.start_rev) - if not commits: - out.error("No commits found") - raise SystemExit(NO_COMMITS_FOUND) tags = git.get_tags() if not tags: tags = [] + if self.incremental: + changelog_meta = changelog.get_metadata(self.file_name) + latest_version = changelog_meta.get("latest_version") + if latest_version: + start_rev = self._find_incremental_rev(latest_version, tags) + + commits = git.get_commits(start=start_rev) + if not commits: + out.error("No commits found") + raise SystemExit(NO_COMMITS_FOUND) + tree = changelog.generate_tree_from_commits( - commits, tags, commit_parser, changelog_pattern + commits, tags, commit_parser, changelog_pattern, unreleased_version ) changelog_out = changelog.render_changelog(tree) - # tag_map = {tag.rev: tag.name for tag in git.get_tags()} - - # entries = OrderedDict() - # # The latest commit is not tagged - # latest_commit = commits[0] - # if latest_commit.rev not in tag_map: - # current_key = "Unreleased" - # entries[current_key] = OrderedDict( - # {value: [] for value in changelog_map.values()} - # ) - # else: - # current_key = tag_map[latest_commit.rev] - - # for commit in commits: - # if commit.rev in tag_map: - # current_key = tag_map[commit.rev] - # entries[current_key] = OrderedDict( - # {value: [] for value in changelog_map.values()} - # ) - - # matches = pat.match(commit.message) - # if not matches: - # continue - - # processed_commit = self.cz.process_commit(commit.message) - # for group_name, commit_type in changelog_map.items(): - # if matches.group(group_name): - # entries[current_key][commit_type].append(processed_commit) - # break - - # template_file = pkg_resources.resource_string( - # __name__, "../templates/keep_a_changelog_template.j2" - # ).decode("utf-8") - # jinja_template = Template(template_file) - # changelog_str = jinja_template.render(entries=entries) + if self.dry_run: out.write(changelog_out) raise SystemExit(0) + lines = [] + if self.incremental and os.path.isfile(self.file_name): + with open(self.file_name, "r") as changelog_file: + lines = changelog_file.readlines() + with open(self.file_name, "w") as changelog_file: - changelog_file.write(changelog_out) + if self.incremental: + new_lines = changelog.incremental_build( + changelog_out, lines, changelog_meta + ) + changelog_file.writelines(new_lines) + else: + changelog_file.write(changelog_out) diff --git a/commitizen/commands/init.py b/commitizen/commands/init.py index b428d696cd..ac73cc295b 100644 --- a/commitizen/commands/init.py +++ b/commitizen/commands/init.py @@ -32,7 +32,9 @@ def __call__(self): values_to_add["version"] = Version(tag).public values_to_add["tag_format"] = self._ask_tag_format(tag) self._update_config_file(values_to_add) - out.write("The configuration are all set.") + out.write("You can bump the version and create cangelog running:\n") + out.info("cz bump --changelog") + out.success("The configuration are all set.") else: # TODO: handle the case that config file exist but no value out.line(f"Config file {self.config.path} already exists") diff --git a/commitizen/defaults.py b/commitizen/defaults.py index 070b415646..1f4adf52e6 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -34,3 +34,4 @@ bump_message = "bump: version $current_version → $new_version" commit_parser = r"^(?P<change_type>feat|fix|refactor|perf|BREAKING CHANGE)(?:\((?P<scope>[^()\r\n]*)\)|\()?(?P<breaking>!)?:\s(?P<message>.*)?" # noqa +version_parser = r"(?P<version>([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+)?)" diff --git a/commitizen/error_codes.py b/commitizen/error_codes.py index 20cc54aa9e..9095399c3f 100644 --- a/commitizen/error_codes.py +++ b/commitizen/error_codes.py @@ -22,3 +22,6 @@ # Check NO_COMMIT_MSG = 13 INVALID_COMMIT_MSG = 14 + +# Changelog +NO_REVISION = 16 diff --git a/commitizen/git.py b/commitizen/git.py index feac0697b0..5c3b5926ee 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -15,6 +15,8 @@ class GitProtocol(Protocol): class GitObject: rev: str + name: str + date: str def __eq__(self, other) -> bool: if not hasattr(other, "rev"): diff --git a/docs/changelog.md b/docs/changelog.md index db8d0bc6ed..b5f4fece2c 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -14,6 +14,16 @@ cz changelog cz ch ``` +It has support for incremental changelog: + +- Build from latest version found in changelog, this is useful if you have a different changelog and want to use chommitizen +- Update unreleased area +- Allows users to manually touch the changelog without being rewritten. + +## Constrains + +At the moment this features is constrained only to markdown files. + ## Description These are the variables used by the changelog generator. @@ -26,7 +36,7 @@ These are the variables used by the changelog generator. - **<scope>**: <message> ``` -It will create a full of the above block per version found in the tags. +It will create a full block like above per version found in the tags. And it will create a list of the commits found. The `change_type` and the `scope` are optional, they don't need to be provided, but if your regex does they will be rendered. @@ -45,5 +55,10 @@ and the following variables are expected: - **required**: is the only one required to be parsed by the regex +## TODO + +- [ ] support for hooks: this would allow introduction of custom information in the commiter, like a github or jira url. Eventually we could build a `CzConventionalGithub`, which would add links to commits +- [ ] support for map: allow the usage of a `change_type` mapper, to convert from feat to feature for example. + [keepachangelog]: https://keepachangelog.com/ [semver]: https://semver.org/ diff --git a/pyproject.toml b/pyproject.toml index 7a2685a783..11306bb4bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,6 +66,7 @@ mypy = "^0.770" mkdocs = "^1.0" mkdocs-material = "^4.1" isort = "^4.3.21" +freezegun = "^0.3.15" [tool.poetry.scripts] cz = "commitizen.cli:main" diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index 981cfa654c..77bb74b522 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -1,8 +1,10 @@ +import os import sys +from datetime import date import pytest -from commitizen import cli +from commitizen import cli, git from tests.utils import create_file_and_commit @@ -15,26 +17,6 @@ def test_changlog_on_empty_project(mocker): cli.main() -@pytest.mark.usefixtures("tmp_commitizen_project") -def test_changlog_from_start(mocker, capsys): - create_file_and_commit("feat: new file") - create_file_and_commit("refactor: not in changelog") - create_file_and_commit("Merge into master") - - testargs = ["cz", "changelog", "--dry-run"] - mocker.patch.object(sys, "argv", testargs) - - with pytest.raises(SystemExit): - cli.main() - - out, _ = capsys.readouterr() - - assert ( - out - == "\n## Unreleased \n\n### Refactor\n\n- not in changelog\n\n### Feat\n\n- new file\n\n" - ) - - @pytest.mark.usefixtures("tmp_commitizen_project") def test_changlog_from_version_zero_point_two(mocker, capsys): create_file_and_commit("feat: new file") @@ -67,3 +49,182 @@ def test_changlog_with_unsupported_cz(mocker, capsys): cli.main() out, err = capsys.readouterr() assert "'cz_jira' rule does not support changelog" in err + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_changlog_from_start(mocker, capsys): + changelog_path = os.path.join(os.getcwd(), "CHANGELOG.md") + create_file_and_commit("feat: new file") + create_file_and_commit("refactor: is in changelog") + create_file_and_commit("Merge into master") + + testargs = ["cz", "changelog"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + + with open(changelog_path, "r") as f: + out = f.read() + + assert ( + out + == "\n## Unreleased \n\n### Refactor\n\n- is in changelog\n\n### Feat\n\n- new file\n" + ) + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_changlog_replacing_unreleased_using_incremental(mocker, capsys): + changelog_path = os.path.join(os.getcwd(), "CHANGELOG.md") + + create_file_and_commit("feat: add new output") + create_file_and_commit("fix: output glitch") + create_file_and_commit("Merge into master") + + testargs = ["cz", "changelog"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + + testargs = ["cz", "bump", "--yes"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + + create_file_and_commit("fix: mama gotta work") + create_file_and_commit("feat: add more stuff") + create_file_and_commit("Merge into master") + + testargs = ["cz", "changelog", "--incremental"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + + with open(changelog_path, "r") as f: + out = f.read() + + today = date.today().isoformat() + assert ( + out + == f"\n\n## Unreleased \n\n### Feat\n\n- add more stuff\n\n### Fix\n\n- mama gotta work\n\n## 0.2.0 ({today})\n\n### Fix\n\n- output glitch\n\n### Feat\n\n- add new output\n" + ) + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_changlog_is_persisted_using_incremental(mocker, capsys): + changelog_path = os.path.join(os.getcwd(), "CHANGELOG.md") + + create_file_and_commit("feat: add new output") + create_file_and_commit("fix: output glitch") + create_file_and_commit("Merge into master") + + testargs = ["cz", "bump", "--yes"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + + testargs = ["cz", "changelog"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + + with open(changelog_path, "a") as f: + f.write("\nnote: this should be persisted using increment\n") + + create_file_and_commit("fix: mama gotta work") + create_file_and_commit("feat: add more stuff") + create_file_and_commit("Merge into master") + + testargs = ["cz", "changelog", "--incremental"] + + mocker.patch.object(sys, "argv", testargs) + cli.main() + + with open(changelog_path, "r") as f: + out = f.read() + + today = date.today().isoformat() + assert ( + out + == f"\n\n## Unreleased \n\n### Feat\n\n- add more stuff\n\n### Fix\n\n- mama gotta work\n\n## 0.2.0 ({today})\n\n### Fix\n\n- output glitch\n\n### Feat\n\n- add new output\n\nnote: this should be persisted using increment\n" + ) + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_changlog_incremental_angular_sample(mocker, capsys): + changelog_path = os.path.join(os.getcwd(), "CHANGELOG.md") + with open(changelog_path, "w") as f: + f.write( + "# [10.0.0-next.3](https://github.com/angular/angular/compare/10.0.0-next.2...10.0.0-next.3) (2020-04-22)\n" + "\n" + "### Bug Fixes" + "\n" + "* **common:** format day-periods that cross midnight ([#36611](https://github.com/angular/angular/issues/36611)) ([c6e5fc4](https://github.com/angular/angular/commit/c6e5fc4)), closes [#36566](https://github.com/angular/angular/issues/36566)\n" + ) + create_file_and_commit("irrelevant commit") + git.tag("10.0.0-next.3") + + create_file_and_commit("feat: add new output") + create_file_and_commit("fix: output glitch") + create_file_and_commit("fix: mama gotta work") + create_file_and_commit("feat: add more stuff") + create_file_and_commit("Merge into master") + + testargs = ["cz", "changelog", "--incremental"] + + mocker.patch.object(sys, "argv", testargs) + cli.main() + + with open(changelog_path, "r") as f: + out = f.read() + + assert ( + out + == "\n## Unreleased \n\n### Feat\n\n- add more stuff\n- add new output\n\n### Fix\n\n- mama gotta work\n- output glitch\n\n# [10.0.0-next.3](https://github.com/angular/angular/compare/10.0.0-next.2...10.0.0-next.3) (2020-04-22)\n\n### Bug Fixes\n* **common:** format day-periods that cross midnight ([#36611](https://github.com/angular/angular/issues/36611)) ([c6e5fc4](https://github.com/angular/angular/commit/c6e5fc4)), closes [#36566](https://github.com/angular/angular/issues/36566)\n" + ) + + +KEEP_A_CHANGELOG = """# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [1.0.0] - 2017-06-20 +### Added +- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8). +- Version navigation. + +### Changed +- Start using "changelog" over "change log" since it's the common usage. + +### Removed +- Section about "changelog" vs "CHANGELOG". + +## [0.3.0] - 2015-12-03 +### Added +- RU translation from [@aishek](https://github.com/aishek). +""" + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_changlog_incremental_keep_a_changelog_sample(mocker, capsys): + changelog_path = os.path.join(os.getcwd(), "CHANGELOG.md") + with open(changelog_path, "w") as f: + f.write(KEEP_A_CHANGELOG) + create_file_and_commit("irrelevant commit") + git.tag("1.0.0") + + create_file_and_commit("feat: add new output") + create_file_and_commit("fix: output glitch") + create_file_and_commit("fix: mama gotta work") + create_file_and_commit("feat: add more stuff") + create_file_and_commit("Merge into master") + + testargs = ["cz", "changelog", "--incremental"] + + mocker.patch.object(sys, "argv", testargs) + cli.main() + + with open(changelog_path, "r") as f: + out = f.read() + + assert ( + out + == """# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n\n## Unreleased \n\n### Feat\n\n- add more stuff\n- add new output\n\n### Fix\n\n- mama gotta work\n- output glitch\n\n## [1.0.0] - 2017-06-20\n### Added\n- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).\n- Version navigation.\n\n### Changed\n- Start using "changelog" over "change log" since it\'s the common usage.\n\n### Removed\n- Section about "changelog" vs "CHANGELOG".\n\n## [0.3.0] - 2015-12-03\n### Added\n- RU translation from [@aishek](https://github.com/aishek).\n""" + ) diff --git a/tests/test_changelog_meta.py b/tests/test_changelog_meta.py new file mode 100644 index 0000000000..505daefb83 --- /dev/null +++ b/tests/test_changelog_meta.py @@ -0,0 +1,165 @@ +import os + +import pytest + +from commitizen import changelog + +CHANGELOG_A = """ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] +- Start using "changelog" over "change log" since it's the common usage. + +## [1.0.0] - 2017-06-20 +### Added +- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8). +- Version navigation. +""".strip() + +CHANGELOG_B = """ +## [Unreleased] +- Start using "changelog" over "change log" since it's the common usage. + +## 1.2.0 +""".strip() + +CHANGELOG_C = """ +# Unreleased + +## v1.0.0 +""" + +CHANGELOG_D = """ +## Unreleased +- Start using "changelog" over "change log" since it's the common usage. +""" + + +@pytest.fixture +def changelog_a_file(): + changelog_path = "tests/CHANGELOG.md" + + with open(changelog_path, "w") as f: + f.write(CHANGELOG_A) + + yield changelog_path + + os.remove(changelog_path) + + +@pytest.fixture +def changelog_b_file(): + changelog_path = "tests/CHANGELOG.md" + + with open(changelog_path, "w") as f: + f.write(CHANGELOG_B) + + yield changelog_path + + os.remove(changelog_path) + + +@pytest.fixture +def changelog_c_file(): + changelog_path = "tests/CHANGELOG.md" + + with open(changelog_path, "w") as f: + f.write(CHANGELOG_C) + + yield changelog_path + + os.remove(changelog_path) + + +@pytest.fixture +def changelog_d_file(): + changelog_path = "tests/CHANGELOG.md" + + with open(changelog_path, "w") as f: + f.write(CHANGELOG_D) + + yield changelog_path + + os.remove(changelog_path) + + +VERSIONS_EXAMPLES = [ + ("## [1.0.0] - 2017-06-20", "1.0.0"), + ( + "# [10.0.0-next.3](https://github.com/angular/angular/compare/10.0.0-next.2...10.0.0-next.3) (2020-04-22)", + "10.0.0-next.3", + ), + ("### 0.19.1 (Jan 7, 2020)", "0.19.1"), + ("## 1.0.0", "1.0.0"), + ("## v1.0.0", "1.0.0"), + ("## v1.0.0 - (2012-24-32)", "1.0.0"), + ("# version 2020.03.24", "2020.03.24"), + ("## [Unreleased]", None), + ("All notable changes to this project will be documented in this file.", None), + ("# Changelog", None), + ("### Bug Fixes", None), +] + + +@pytest.mark.parametrize("line_from_changelog,output_version", VERSIONS_EXAMPLES) +def test_changelog_detect_version(line_from_changelog, output_version): + version = changelog.parse_version_from_markdown(line_from_changelog) + assert version == output_version + + +TITLES_EXAMPLES = [ + ("## [1.0.0] - 2017-06-20", "##"), + ("## [Unreleased]", "##"), + ("# Unreleased", "#"), +] + + +@pytest.mark.parametrize("line_from_changelog,output_title", TITLES_EXAMPLES) +def test_parse_title_type_of_line(line_from_changelog, output_title): + title = changelog.parse_title_type_of_line(line_from_changelog) + assert title == output_title + + +def test_get_metadata_from_a(changelog_a_file): + meta = changelog.get_metadata(changelog_a_file) + assert meta == { + "latest_version": "1.0.0", + "latest_version_position": 10, + "unreleased_end": 10, + "unreleased_start": 7, + } + + +def test_get_metadata_from_b(changelog_b_file): + meta = changelog.get_metadata(changelog_b_file) + assert meta == { + "latest_version": "1.2.0", + "latest_version_position": 3, + "unreleased_end": 3, + "unreleased_start": 0, + } + + +def test_get_metadata_from_c(changelog_c_file): + meta = changelog.get_metadata(changelog_c_file) + assert meta == { + "latest_version": "1.0.0", + "latest_version_position": 3, + "unreleased_end": 3, + "unreleased_start": 1, + } + + +def test_get_metadata_from_d(changelog_d_file): + meta = changelog.get_metadata(changelog_d_file) + assert meta == { + "latest_version": None, + "latest_version_position": None, + "unreleased_end": 2, + "unreleased_start": 1, + } diff --git a/tests/test_changelog_parser.py b/tests/test_changelog_parser.py index 352447ae26..f07d8c3f63 100644 --- a/tests/test_changelog_parser.py +++ b/tests/test_changelog_parser.py @@ -33,7 +33,7 @@ def changelog_content() -> str: @pytest.fixture -def existing_changelog_file(request): +def existing_changelog_file(): changelog_path = "tests/CHANGELOG.md" with open(changelog_path, "w") as f: From 7cfb4e5312f5df977e487102df21213bf274e761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 2 May 2020 12:33:46 +0200 Subject: [PATCH 084/427] feat(changelog): add support for any commit rule system --- commitizen/cz/base.py | 10 +++++++--- commitizen/templates/keep_a_changelog_template.j2 | 2 +- tests/commands/test_changelog_command.py | 12 +++++++++--- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/commitizen/cz/base.py b/commitizen/cz/base.py index 207be89d1d..c6e74d95b0 100644 --- a/commitizen/cz/base.py +++ b/commitizen/cz/base.py @@ -9,8 +9,6 @@ class BaseCommitizen(metaclass=ABCMeta): bump_pattern: Optional[str] = None bump_map: Optional[dict] = None - changelog_pattern: Optional[str] = None - changelog_map: Optional[dict] = None default_style_config: List[Tuple[str, str]] = [ ("qmark", "fg:#ff9d00 bold"), ("question", "bold"), @@ -23,7 +21,13 @@ class BaseCommitizen(metaclass=ABCMeta): ("text", ""), ("disabled", "fg:#858585 italic"), ] - commit_parser: Optional[str] = None + + # The whole subject will be parsed as message by default + # This allows supporting changelog for any rule system. + # It can be modified per rule + commit_parser: Optional[str] = r"(?P<message>.*)" + changelog_pattern: Optional[str] = r".*" + changelog_map: Optional[dict] = None # TODO: Use it def __init__(self, config: BaseConfig): self.config = config diff --git a/commitizen/templates/keep_a_changelog_template.j2 b/commitizen/templates/keep_a_changelog_template.j2 index a0fadb0223..be0d0d26e6 100644 --- a/commitizen/templates/keep_a_changelog_template.j2 +++ b/commitizen/templates/keep_a_changelog_template.j2 @@ -11,7 +11,7 @@ {% for change in changes %} {% if change.scope %} - **{{ change.scope }}**: {{ change.message }} -{% else %} +{% elif change.message %} - {{ change.message }} {% endif %} {% endfor %} diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index 77bb74b522..d78d04bee2 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -41,14 +41,20 @@ def test_changlog_from_version_zero_point_two(mocker, capsys): @pytest.mark.usefixtures("tmp_commitizen_project") -def test_changlog_with_unsupported_cz(mocker, capsys): +def test_changlog_with_different_cz(mocker, capsys): + create_file_and_commit("JRA-34 #comment corrected indent issue") + create_file_and_commit("JRA-35 #time 1w 2d 4h 30m Total work logged") + testargs = ["cz", "-n", "cz_jira", "changelog", "--dry-run"] mocker.patch.object(sys, "argv", testargs) with pytest.raises(SystemExit): cli.main() - out, err = capsys.readouterr() - assert "'cz_jira' rule does not support changelog" in err + out, _ = capsys.readouterr() + assert ( + out + == "\n## Unreleased \n\n\n- JRA-35 #time 1w 2d 4h 30m Total work logged\n- JRA-34 #comment corrected indent issue\n\n" + ) @pytest.mark.usefixtures("tmp_commitizen_project") From 9b407991b291cbbf6489fd0873e2bbd5eb6c3c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 2 May 2020 12:44:12 +0200 Subject: [PATCH 085/427] docs(changelog): update information about using changelog command --- docs/changelog.md | 85 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 8 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index b5f4fece2c..fab38ea2ad 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -4,7 +4,28 @@ This command will generate a changelog following the commiting rules established ## Usage -In the command line run +```bash +$ cz changelog --help +usage: cz changelog [-h] [--dry-run] [--file-name FILE_NAME] + [--unreleased-version UNRELEASED_VERSION] [--incremental] + [--start-rev START_REV] + +optional arguments: + -h, --help show this help message and exit + --dry-run show changelog to stdout + --file-name FILE_NAME + file name of changelog (default: 'CHANGELOG.md') + --unreleased-version UNRELEASED_VERSION + set the value for the new version (use the tag value), + instead of using unreleased + --incremental generates changelog from last created version, useful + if the changelog has been manually modified + --start-rev START_REV + start rev of the changelog.If not set, it will + generate changelog from the start +``` + +### Examples ```bash cz changelog @@ -14,15 +35,9 @@ cz changelog cz ch ``` -It has support for incremental changelog: - -- Build from latest version found in changelog, this is useful if you have a different changelog and want to use chommitizen -- Update unreleased area -- Allows users to manually touch the changelog without being rewritten. - ## Constrains -At the moment this features is constrained only to markdown files. +changelog generation is constrained only to **markdown** files. ## Description @@ -55,6 +70,60 @@ and the following variables are expected: - **required**: is the only one required to be parsed by the regex +## Configuration + +### `unreleased_version` + +There is usually an egg and chicken situation when automatically +bumping the version and creating the changelog. +If you bump the version first, you have no changelog, you have to +create it later, and it won't be included in +the release of the created version. + +If you create the changelog before bumping the version, then you +usually don't have the latest tag, and the _Unreleased_ title appears. + +By introducing `unreleased_version` you can prevent this situation. + +Before bumping you can run: + +```bash +cz changelog --unreleased_version="v1.0.0" +``` + +Remember to use the tag instead of the raw version number + +For example if the format of your tag includes a `v` (`v1.0.0`), then you should use that, +if your tag is the same as the raw version, then ignore this. + +Alternatively you can directly bump the version and create the changelog by doing + +```bash +cz bump --changelog +``` + +### `file-name` + +This value can be updated in the `toml` file with the key `changelog_file` under `tools.commitizen` + +Specify the name of the output file, remember that changelog only works with markdown. + +```bash +cz changelog --file-name="CHANGES.md" +``` + +### `incremental` + +Benefits: + +- Build from latest version found in changelog, this is useful if you have a different changelog and want to use commitizen +- Update unreleased area +- Allows users to manually touch the changelog without being rewritten. + +```bash +cz changelog --incremental +``` + ## TODO - [ ] support for hooks: this would allow introduction of custom information in the commiter, like a github or jira url. Eventually we could build a `CzConventionalGithub`, which would add links to commits From 69402415f2b3012bf163ce9d03c6e9152def2bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 2 May 2020 12:45:58 +0200 Subject: [PATCH 086/427] docs(bump): add information about changelog --- docs/bump.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/bump.md b/docs/bump.md index 393baefd15..d9527135e4 100644 --- a/docs/bump.md +++ b/docs/bump.md @@ -54,7 +54,7 @@ Some examples: ```bash $ cz bump --help -usage: cz bump [-h] [--dry-run] [--files-only] [--yes] +usage: cz bump [-h] [--dry-run] [--files-only] [--changelog] [--yes] [--tag-format TAG_FORMAT] [--bump-message BUMP_MESSAGE] [--prerelease {alpha,beta,rc}] [--increment {MAJOR,MINOR,PATCH}] @@ -63,10 +63,11 @@ 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 + --changelog, -ch generate the changelog for the newest version --yes accept automatically questions done --tag-format TAG_FORMAT - the format used to tag the commit and read it, use it in - existing projects, wrap around simple quotes + the format used to tag the commit and read it, use it + in existing projects, wrap around simple quotes --bump-message BUMP_MESSAGE template used to create the release commmit, useful when working with CI @@ -78,6 +79,14 @@ optional arguments: ## Configuration +### `changelog` + +Generate a **changelog** along with the new version and tag when bumping. + +```bash +cz bump --changelog +``` + ### `tag_format` It is used to read the format from the git tags, and also to generate the tags. From 5fec1d48bfd67622a6713ed3e4595f3451c7d325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 2 May 2020 16:04:47 +0200 Subject: [PATCH 087/427] ci(bumpversion): generate changelog along with the version --- .github/workflows/bumpversion.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bumpversion.yml b/.github/workflows/bumpversion.yml index f7559b420b..90c8af6373 100644 --- a/.github/workflows/bumpversion.yml +++ b/.github/workflows/bumpversion.yml @@ -32,7 +32,7 @@ jobs: git pull origin master --tags - name: Create bump run: | - cz bump --yes + cz bump --yes --changelog git tag - name: Push changes uses: Woile/github-push-action@master From aca2fe929f3321af8e92bd5197f0fbc83e0ea23d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 2 May 2020 16:07:15 +0200 Subject: [PATCH 088/427] fix(changelog): check get_metadata for existing changelog file --- commitizen/changelog.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/commitizen/changelog.py b/commitizen/changelog.py index 9596dcb027..3990b4cfb5 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -25,6 +25,7 @@ - [ ] hook after changelog is generated (api calls) - [ ] add support for change_type maps """ +import os import re from collections import defaultdict from typing import Dict, Iterable, List, Optional @@ -157,6 +158,14 @@ def get_metadata(filepath: str) -> Dict: unreleased_title: Optional[str] = None latest_version: Optional[str] = None latest_version_position: Optional[int] = None + if not os.path.isfile(filepath): + return { + "unreleased_start": None, + "unreleased_end": None, + "latest_version": None, + "latest_version_position": None, + } + with open(filepath, "r") as changelog_file: for index, line in enumerate(changelog_file): line = line.strip().lower() From 7e0853c867cfc6c3c3945fef45b45592ded1eaef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 2 May 2020 12:49:57 +0200 Subject: [PATCH 089/427] ci: separate docs from python publishing Closes #171 --- .github/workflows/docspublish.yaml | 33 ++++++++++++++++++++++++++++ .github/workflows/pythonpublish.yaml | 11 ++-------- 2 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/docspublish.yaml diff --git a/.github/workflows/docspublish.yaml b/.github/workflows/docspublish.yaml new file mode 100644 index 0000000000..d671c73c26 --- /dev/null +++ b/.github/workflows/docspublish.yaml @@ -0,0 +1,33 @@ +name: Publish documentation + +on: + push: + branches: + - master + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + token: '${{ secrets.PERSONAL_ACCESS_TOKEN }}' + fetch-depth: 0 + - name: Set up Python + uses: actions/setup-python@v1 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install -U mkdocs mkdocs-material + - name: Build docs + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + python -m mkdocs build + - name: Push doc to Github Page + uses: peaceiris/actions-gh-pages@v2 + env: + PERSONAL_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + PUBLISH_BRANCH: gh-pages + PUBLISH_DIR: ./site diff --git a/.github/workflows/pythonpublish.yaml b/.github/workflows/pythonpublish.yaml index e6d5cad1ee..937d6aa387 100644 --- a/.github/workflows/pythonpublish.yaml +++ b/.github/workflows/pythonpublish.yaml @@ -22,17 +22,10 @@ jobs: python -m pip install --pre -U poetry mkdocs mkdocs-material poetry --version poetry install - - name: Build and publish + - name: Publish env: PYPI_USERNAME: ${{ secrets.PYPI_USERNAME }} PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | ./scripts/publish - poetry run mkdocs build - - name: Push doc to Github Page - uses: peaceiris/actions-gh-pages@v2 - env: - PERSONAL_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} - PUBLISH_BRANCH: gh-pages - PUBLISH_DIR: ./site + From 6e3597d07c5068b94c76187b6179a05f20d2f9a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 2 May 2020 20:33:26 +0200 Subject: [PATCH 090/427] ci: use commitizen from master branch instead of pypi --- .github/workflows/bumpversion.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/bumpversion.yml b/.github/workflows/bumpversion.yml index 90c8af6373..54c945d595 100644 --- a/.github/workflows/bumpversion.yml +++ b/.github/workflows/bumpversion.yml @@ -24,15 +24,16 @@ jobs: - name: Install dependencies run: | python --version - python -m pip install -U commitizen + python -m pip install -U poetry - name: Configure repo run: | git config --local user.email "action@github.com" git config --local user.name "GitHub Action" git pull origin master --tags + poetry install --no-dev - name: Create bump run: | - cz bump --yes --changelog + poetry run cz bump --yes --changelog git tag - name: Push changes uses: Woile/github-push-action@master From ba64169d87e848e928f07c90fdc9e65afb6b870d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 2 May 2020 20:40:18 +0200 Subject: [PATCH 091/427] fix(git): missing dependency removed --- commitizen/git.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/commitizen/git.py b/commitizen/git.py index f6a00a9656..227f6c51a3 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -3,16 +3,9 @@ from tempfile import NamedTemporaryFile from typing import List, Optional -from typing_extensions import Protocol - from commitizen import cmd -class GitProtocol(Protocol): - rev: str - name: str - - class GitObject: rev: str name: str From 62c3af50e6a0d992b53961e1f31ad7e7fc678c3f Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sat, 2 May 2020 18:41:11 +0000 Subject: [PATCH 092/427] =?UTF-8?q?bump:=20version=201.18.3=20=E2=86=92=20?= =?UTF-8?q?1.19.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 64 ++++++++++++++++++++++++++++++++++++++- commitizen/__version__.py | 2 +- pyproject.toml | 4 +-- 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8736827ae..7987d5c7f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,34 @@ -## Unreleased + +## v1.19.0 + +### Fix + +- **git**: missing dependency removed +- **changelog**: check get_metadata for existing changelog file + +### Feat + +- **changelog**: add support for any commit rule system +- **changelog**: add incremental flag ### Refactor +- **changelog**: use functions from changelog.py - **changelog**: rename category to change_type to fit 'keep a changelog' + +## v1.18.3 (2020-04-22) + +### Refactor + +- **commands/init**: fix typo + +## v1.18.2 (2020-04-22) + +### Refactor + +- **git**: replace GitCommit.message code with one-liner - **templates**: rename as "keep_a_changelog_template.j2" - **templates**: remove unneeded __init__ file - **cli**: reorder commands @@ -15,6 +39,7 @@ ### Fix +- **git**: fix returned value for GitCommit.message when body is empty - **cz/conventional_commits**: fix schema_pattern break due to rebase - **changelog_template**: fix list format - **commitizen/cz**: set changelog_map, changelog_pattern to none as default @@ -32,6 +57,43 @@ - **cz/base**: add default process_commit for processing commit message - **changelog**: changelog tree generation from markdown +## v1.18.1 (2020-04-16) + +### Fix + +- **config**: display ini config deprecation warning only when commitizen config is inside + +## v1.18.0 (2020-04-13) + +### Refactor + +- **cz/customize**: remove unused mypy ignore +- **mypy**: fix mypy check by checking version.pre exists +- **cz**: add type annotation to registry +- **commands/check**: fix type annotation +- **config/base**: use Dict to replace dict in base_config +- **cz/base**: fix config type used in base cz +- **cz**: add type annotation for each function in cz +- **config**: fix mypy warning for _conf + +### Fix + +- **cz/customize**: add error handling when customize detail is not set + +### Feat + +- **bump**: support for ! as BREAKING change in commit message + +## v1.17.1 (2020-03-24) + +### Fix + +- **commands/check**: add help text for check command without argument + +### Refactor + +- **cli**: fix typo + ## v1.17.0 (2020-03-15) ### Refactor diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 14e8848aa1..d84d79d43f 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.18.3" +__version__ = "1.19.0" diff --git a/pyproject.toml b/pyproject.toml index 0c26efd7ad..9c881969da 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.18.3" +version = "1.19.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.18.3" +version = "1.19.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 5ed9461d9e59dd97908b9e2307781c01019b7f34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 2 May 2020 20:49:56 +0200 Subject: [PATCH 093/427] docs: add changelog to mkdocs --- docs/README.md | 2 +- mkdocs.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index edb03dcefb..8aee8e4ea0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -28,7 +28,7 @@ the version or a changelog. - Command-line utility to create commits with your rules. Defaults: [Conventional commits][conventional_commits] - Display information about your commit rules (commands: schema, example, info) - Bump version automatically using [semantic versioning][semver] based on the commits. [Read More](./bump.md) -- Generate a changelog using [Keep a changelog][keepchangelog] (Planned feature) +- Generate a changelog using [Keep a changelog][keepchangelog] ## Requirements diff --git a/mkdocs.yml b/mkdocs.yml index 42a03ca2ee..52ef5415ad 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -14,6 +14,7 @@ nav: - Init: 'init.md' - Bump: 'bump.md' - Check: 'check.md' + - Changelog: 'changelog.md' - Configuration: 'config.md' - Customization: 'customization.md' - Tutorials: From 13da44d649b8332a167f69dde42279bc6b8261b5 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 3 May 2020 13:06:45 +0800 Subject: [PATCH 094/427] refactor(cli): add explicit category for deprecation warnings --- commitizen/cli.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index f5b41a2e2f..d457d8b7ec 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -247,15 +247,21 @@ def main(): if args.version: warnings.warn( - "'cz --version' will be deprecated in next major version. " - "Please use 'cz version' command from your scripts" + ( + "'cz --version' will be deprecated in next major version. " + "Please use 'cz version' command from your scripts" + ), + category=DeprecationWarning, ) args.func = commands.Version if args.debug: warnings.warn( - "Debug will be deprecated in next major version. " - "Please remove it from your scripts" + ( + "Debug will be deprecated in next major version. " + "Please remove it from your scripts" + ), + category=DeprecationWarning, ) logging.getLogger("commitizen").setLevel(logging.DEBUG) From fc2ca6994c10e6f5781965f1d5ad2f651249f6c6 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 3 May 2020 13:07:07 +0800 Subject: [PATCH 095/427] test(cli): cover test for warnings --- tests/test_cli.py | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index e136096f37..4275fa23ce 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -55,10 +55,29 @@ def test_ls(mocker, capsys): assert isinstance(out, str) -def test_version(mocker, capsys): +def test_arg_version(mocker, capsys): testargs = ["cz", "--version"] mocker.patch.object(sys, "argv", testargs) - cli.main() - out, _ = capsys.readouterr() - assert out.strip() == __version__ + with pytest.warns(DeprecationWarning) as record: + cli.main() + out, _ = capsys.readouterr() + assert out.strip() == __version__ + + assert record[0].message.args[0] == ( + "'cz --version' will be deprecated in next major version. " + "Please use 'cz version' command from your scripts" + ) + + +def test_arg_debug(mocker): + testargs = ["cz", "--debug", "info"] + mocker.patch.object(sys, "argv", testargs) + + with pytest.warns(DeprecationWarning) as record: + cli.main() + + assert record[0].message.args[0] == ( + "Debug will be deprecated in next major version. " + "Please remove it from your scripts" + ) From a78f2438bebc02794cef96bb83bf5a3235956f59 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 3 May 2020 13:36:20 +0800 Subject: [PATCH 096/427] fix(commands/check): Show warning if no commit to check when running `cz check --rev-range` #165 --- commitizen/commands/check.py | 7 ++++++- tests/commands/test_check_command.py | 8 ++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py index ccfb7a4791..beadc4b392 100644 --- a/commitizen/commands/check.py +++ b/commitizen/commands/check.py @@ -1,10 +1,11 @@ import os import re +import warnings from typing import Dict, Optional from commitizen import factory, git, out from commitizen.config import BaseConfig -from commitizen.error_codes import INVALID_COMMIT_MSG +from commitizen.error_codes import INVALID_COMMIT_MSG, NO_COMMITS_FOUND class Check: @@ -50,6 +51,10 @@ def __call__(self): """ commit_msgs = self._get_commit_messages() + if not commit_msgs: + warnings.warn(f"No commit found with range: '{self.rev_range}'") + raise SystemExit(NO_COMMITS_FOUND) + pattern = self.cz.schema_pattern() for commit_msg in commit_msgs: if not Check.validate_commit_message(commit_msg, pattern): diff --git a/tests/commands/test_check_command.py b/tests/commands/test_check_command.py index e5fe53b518..bfa3d6bd88 100644 --- a/tests/commands/test_check_command.py +++ b/tests/commands/test_check_command.py @@ -194,3 +194,11 @@ def test_check_command_with_invalid_argment(args, config, capsys): commands.Check(config=config, arguments=args) _, err = capsys.readouterr() assert "One and only one argument is required for check command!" in err + + +def test_check_command_with_empty_range(config, mocker, capsys): + check_cmd = commands.Check(config=config, arguments={"rev_range": "master..master"}) + with pytest.raises(SystemExit), pytest.warns(UserWarning) as record: + check_cmd() + + assert record[0].message.args[0] == "No commit found with range: 'master..master'" From 07c1a16b74fdf12cc24c1ff3c87e7987671fd2b8 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sun, 3 May 2020 08:27:38 +0000 Subject: [PATCH 097/427] =?UTF-8?q?bump:=20version=201.19.0=20=E2=86=92=20?= =?UTF-8?q?1.19.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 11 +++++++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7987d5c7f7..f2e6fa4fe0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,17 @@ + +## v1.19.1 + +### Fix + +- **commands/check**: Show warning if no commit to check when running `cz check --rev-range` + +### Refactor + +- **cli**: add explicit category for deprecation warnings + ## v1.19.0 ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index d84d79d43f..90fa0968e4 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.19.0" +__version__ = "1.19.1" diff --git a/pyproject.toml b/pyproject.toml index 9c881969da..ddb8c6f1fe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.19.0" +version = "1.19.1" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.19.0" +version = "1.19.1" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 99fc13eee512a755f4ee27f8d9dbd11d6b538b13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sun, 3 May 2020 10:16:15 +0200 Subject: [PATCH 098/427] fix(changelog): sort the commits properly to their version --- CHANGELOG.md | 30 +++++++++++++----------------- commitizen/commands/changelog.py | 2 +- commitizen/git.py | 5 +++-- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2e6fa4fe0..0daacbe257 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,11 @@ +## Unreleased +### Fix +- **changelog**: sort the commits properly to their version -## v1.19.1 +## v1.19.1 (2020-05-03) ### Fix @@ -12,7 +15,7 @@ - **cli**: add explicit category for deprecation warnings -## v1.19.0 +## v1.19.0 (2020-05-02) ### Fix @@ -24,11 +27,6 @@ - **changelog**: add support for any commit rule system - **changelog**: add incremental flag -### Refactor - -- **changelog**: use functions from changelog.py -- **changelog**: rename category to change_type to fit 'keep a changelog' - ## v1.18.3 (2020-04-22) ### Refactor @@ -40,6 +38,8 @@ ### Refactor - **git**: replace GitCommit.message code with one-liner +- **changelog**: use functions from changelog.py +- **changelog**: rename category to change_type to fit 'keep a changelog' - **templates**: rename as "keep_a_changelog_template.j2" - **templates**: remove unneeded __init__ file - **cli**: reorder commands @@ -175,20 +175,20 @@ ### Refactor - **tests/commands/bump**: use tmp_dir to replace self implemented tmp dir behavior +- **git**: make find_git_project_root return None if it's not a git project +- **config/base_config**: make set_key not implemented +- **error_codes**: move all the error_codes to a module +- **config**: replace string type path with pathlib.Path - **test_bump_command**: rename camel case variables - **tests/commands/check**: use pytest fixture tmpdir replace self implemented contextmanager - **test/commands/other**: replace unit test style mock with mocker fixture - **tests/commands**: separate command unit tests into modules - **tests/commands**: make commands related tests a module -- **git**: make find_git_project_root return None if it's not a git project -- **config/base_config**: make set_key not implemented -- **error_codes**: move all the error_codes to a module -- **config**: replace string type path with pathlib.Path ### Fix -- **cli**: fix --version not functional - **git**: remove breakline in the return value of find_git_project_root +- **cli**: fix --version not functional ### Feat @@ -298,10 +298,10 @@ - **config**: add deprecation warning for loading config from ini files - **cz/customize**: add jinja support to enhance template flexibility - **cz/filters**: add required_validator and multiple_line_breaker -- **Commands/commit**: add ´--dry-run´ flag to the Commit command - **cz/cz_customize**: implement info to support info and info_path - **cz/cz_customize**: enable bump_pattern bump_map customization - **cz/cz_customize**: implement customizable cz +- **Commands/commit**: add ´--dry-run´ flag to the Commit command - new 'git-cz' entrypoint ### Refactor @@ -512,10 +512,6 @@ ## v0.9.2 (2017-11-11) -### Refactor - -- **renamed conventional_changelog to conventional_commits, not backward compatible**: - ## v0.9.1 (2017-11-11) ### Fix diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 12f43f775d..0d6f8bb426 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -77,7 +77,7 @@ def __call__(self): if latest_version: start_rev = self._find_incremental_rev(latest_version, tags) - commits = git.get_commits(start=start_rev) + commits = git.get_commits(start=start_rev, args="--author-date-order") if not commits: out.error("No commits found") raise SystemExit(NO_COMMITS_FOUND) diff --git a/commitizen/git.py b/commitizen/git.py index 227f6c51a3..76abb17ade 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -46,7 +46,7 @@ def tag(tag: str): return c -def commit(message: str, args=""): +def commit(message: str, args: str = ""): f = NamedTemporaryFile("wb", delete=False) f.write(message.encode("utf-8")) f.close() @@ -61,11 +61,12 @@ def get_commits( *, log_format: str = "%H%n%s%n%b", delimiter: str = "----------commit-delimiter----------", + args: str = "", ) -> List[GitCommit]: """ Get the commits betweeen start and end """ - git_log_cmd = f"git log --pretty={log_format}{delimiter}" + git_log_cmd = f"git log --pretty={log_format}{delimiter} {args}" if start: c = cmd.run(f"{git_log_cmd} {start}..{end}") From 75fe50f9e9fee49c38bd7c2d80bf02de306bef28 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sun, 3 May 2020 08:32:59 +0000 Subject: [PATCH 099/427] =?UTF-8?q?bump:=20version=201.19.1=20=E2=86=92=20?= =?UTF-8?q?1.19.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 ++- commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0daacbe257..2b2138c420 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ -## Unreleased + +## v1.19.2 ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 90fa0968e4..d388c7ab71 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.19.1" +__version__ = "1.19.2" diff --git a/pyproject.toml b/pyproject.toml index ddb8c6f1fe..031b3a1542 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.19.1" +version = "1.19.2" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.19.1" +version = "1.19.2" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 2fe9c74fccd0fa8a31435f238f3e033dd4bcc783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sun, 3 May 2020 10:48:48 +0200 Subject: [PATCH 100/427] fix(changelog): generate today's date when using an unreleased_version --- CHANGELOG.md | 3 +-- commitizen/changelog.py | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b2138c420..64c24e45bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,5 @@ - -## v1.19.2 +## v1.19.2 (2020-05-03) ### Fix diff --git a/commitizen/changelog.py b/commitizen/changelog.py index 3990b4cfb5..099c647ece 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -28,6 +28,7 @@ import os import re from collections import defaultdict +from datetime import date from typing import Dict, Iterable, List, Optional import pkg_resources @@ -80,6 +81,8 @@ def generate_tree_from_commits( current_tag_name: str = unreleased_version or "Unreleased" current_tag_date: str = "" + if unreleased_version is not None: + current_tag_date = date.today().isoformat() if current_tag is not None and current_tag.name: current_tag_name = current_tag.name current_tag_date = current_tag.date From 4a1aee85f240d730baed1fda3bb225813494157b Mon Sep 17 00:00:00 2001 From: Kudlaty <kfuks2@gmail.com> Date: Mon, 4 May 2020 18:29:52 +0200 Subject: [PATCH 101/427] fix(docs): change old url woile.github.io to commitizen-tools.github.io --- docs/config.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/config.md b/docs/config.md index 67ce1f9a4f..a34292975e 100644 --- a/docs/config.md +++ b/docs/config.md @@ -67,9 +67,9 @@ The extra tab before the square brackets (`]`) at the end is required. | -------- | ---- | ------- | ----------- | | `name` | `str` | `"cz_conventional_commits"` | Name of the committing rules to use | | `version` | `str` | `None` | Current version. Example: "0.1.2" | -| `version_files` | `list` | `[ ]` | Files were the version will be updated. A pattern to match a line, can also be specified, separated by `:` [See more](https://woile.github.io/commitizen/bump#files) | -| `tag_format` | `str` | `None` | Format for the git tag, useful for old projects, that use a convention like `"v1.2.1"`. [See more](https://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) | +| `version_files` | `list` | `[ ]` | Files were the version will be updated. A pattern to match a line, can also be specified, separated by `:` [See more](https://commitizen-tools.github.io/commitizen/bump/#version_files) | +| `tag_format` | `str` | `None` | Format for the git tag, useful for old projects, that use a convention like `"v1.2.1"`. [See more](https://commitizen-tools.github.io/commitizen/bump/#tag_format) | +| `bump_message` | `str` | `None` | Create custom commit message, useful to skip ci. [See more](https://commitizen-tools.github.io/commitizen/bump/#bump_message) | | `changelog_file` | `str` | `CHANGELOG.md` | filename of exported changelog | | `style` | `list` | see above | Style for the prompts (It will merge this value with default style.) [See More (Styling your prompts with your favorite colors)](https://github.com/tmbo/questionary#additional-features) | | `customize` | `dict` | `None` | **This is only supported when config through `toml`.** Custom rules for committing and bumping. [See more](https://commitizen-tools.github.io/commitizen/customization/) | From 86f67fd156ab0f855977d40797117c195062ccfb Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Mon, 4 May 2020 17:23:50 +0000 Subject: [PATCH 102/427] =?UTF-8?q?bump:=20version=201.19.2=20=E2=86=92=20?= =?UTF-8?q?1.19.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 8 ++++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64c24e45bc..96908a7b9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,12 @@ + +## v1.19.3 (2020-05-04) + +### Fix + +- **docs**: change old url woile.github.io to commitizen-tools.github.io +- **changelog**: generate today's date when using an unreleased_version + ## v1.19.2 (2020-05-03) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index d388c7ab71..f27cba7c78 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.19.2" +__version__ = "1.19.3" diff --git a/pyproject.toml b/pyproject.toml index 031b3a1542..c913ecad8d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.19.2" +version = "1.19.3" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.19.2" +version = "1.19.3" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 8dd079ee86d64842c321825867dec17d9597bb0b Mon Sep 17 00:00:00 2001 From: Kudlaty <kfuks2@gmail.com> Date: Mon, 4 May 2020 18:08:42 +0200 Subject: [PATCH 103/427] feat(bump): add optional --no-verify argument for bump command --- commitizen/cli.py | 6 ++++++ commitizen/commands/bump.py | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index d457d8b7ec..8fea00400e 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -92,6 +92,12 @@ "default": False, "help": "generate the changelog for the newest version", }, + { + "name": ["--no-verify"], + "action": "store_true", + "default": False, + "help": "this option bypasses the pre-commit and commit-msg hooks", + }, { "name": "--yes", "action": "store_true", diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 1d0439e4b9..80a9a8ebcd 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -31,6 +31,7 @@ def __init__(self, config: BaseConfig, arguments: dict): } self.cz = factory.commiter_factory(self.config) self.changelog = arguments["changelog"] + self.no_verify = arguments["no_verify"] def is_initial_tag(self, current_tag_version: str, is_yes: bool = False) -> bool: """Check if reading the whole git tree up to HEAD is needed.""" @@ -145,7 +146,7 @@ def __call__(self): # noqa: C901 changelog() self.config.set_key("version", new_version.public) - c = git.commit(message, args="-a") + c = git.commit(message, args=self._get_commit_args()) if c.err: out.error('git.commit errror: "{}"'.format(c.err.strip())) raise SystemExit(COMMIT_FAILED) @@ -154,3 +155,9 @@ def __call__(self): # noqa: C901 out.error(c.err) raise SystemExit(TAG_FAILED) out.success("Done!") + + def _get_commit_args(self): + commit_args = ["-a"] + if self.no_verify: + commit_args.append("--no-verify") + return " ".join(commit_args) From b8f2894682827c53c37b473b457a9d61b637f12a Mon Sep 17 00:00:00 2001 From: Kudlaty <kfuks2@gmail.com> Date: Tue, 5 May 2020 07:44:37 +0200 Subject: [PATCH 104/427] docs(bump): add info about --no-verify option --- docs/bump.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/bump.md b/docs/bump.md index d9527135e4..a70c35d303 100644 --- a/docs/bump.md +++ b/docs/bump.md @@ -54,7 +54,7 @@ Some examples: ```bash $ cz bump --help -usage: cz bump [-h] [--dry-run] [--files-only] [--changelog] [--yes] +usage: cz bump [-h] [--dry-run] [--files-only] [--changelog] [--no-verify] [--yes] [--tag-format TAG_FORMAT] [--bump-message BUMP_MESSAGE] [--prerelease {alpha,beta,rc}] [--increment {MAJOR,MINOR,PATCH}] @@ -64,6 +64,7 @@ optional arguments: --dry-run show output to stdout, no commit, no modified files --files-only bump version in the files from the config --changelog, -ch generate the changelog for the newest version + --no-verify this option bypasses the pre-commit and commit-msg hooks --yes accept automatically questions done --tag-format TAG_FORMAT the format used to tag the commit and read it, use it From 638b38a7ee52d86761031d503004d3b8031a2657 Mon Sep 17 00:00:00 2001 From: Kudlaty <kfuks2@gmail.com> Date: Tue, 5 May 2020 15:07:45 +0200 Subject: [PATCH 105/427] test(bump): add test for --no-verify option --- tests/commands/test_bump_command.py | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index 3907d19527..5ce0228d36 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -59,6 +59,44 @@ def test_bump_command(mocker): assert tag_exists is True +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_bump_on_git_with_hooks_no_verify_disabled(mocker, capsys): + cmd.run("mkdir .git/hooks") + with open(".git/hooks/pre-commit", "w") as f: + f.write("#!/usr/bin/env bash\n" 'echo "0.1.0"') + cmd.run("chmod +x .git/hooks/pre-commit") + + # MINOR + create_file_and_commit("feat: new file") + + testargs = ["cz", "bump", "--yes"] + mocker.patch.object(sys, "argv", testargs) + + with pytest.raises(SystemExit): + cli.main() + + _, err = capsys.readouterr() + assert 'git.commit errror: "0.1.0"' in err + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_bump_on_git_with_hooks_no_verify_enabled(mocker): + cmd.run("mkdir .git/hooks") + with open(".git/hooks/pre-commit", "w") as f: + f.write("#!/usr/bin/env bash\n" 'echo "0.1.0"') + cmd.run("chmod +x .git/hooks/pre-commit") + + # MINOR + create_file_and_commit("feat: new file") + + testargs = ["cz", "bump", "--yes", "--no-verify"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + + tag_exists = git.tag_exist("0.2.0") + assert tag_exists is True + + def test_bump_when_bumpping_is_not_support(mocker, capsys, tmpdir): with tmpdir.as_cwd(): with open("./pyproject.toml", "w") as f: From 18f3231f36e1a544ba3164c3a2db962ba76b9cbd Mon Sep 17 00:00:00 2001 From: Kudlaty <kfuks2@gmail.com> Date: Tue, 5 May 2020 19:05:20 +0200 Subject: [PATCH 106/427] ci(github/bumpversion): fix workflow to not skip commits with bump word --- .github/workflows/bumpversion.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bumpversion.yml b/.github/workflows/bumpversion.yml index 54c945d595..dfaaa216e7 100644 --- a/.github/workflows/bumpversion.yml +++ b/.github/workflows/bumpversion.yml @@ -7,7 +7,7 @@ on: jobs: build: - if: "!contains(github.event.head_commit.message, 'bump')" + if: "!startsWith(github.event.head_commit.message, 'bump:')" runs-on: ubuntu-latest strategy: matrix: From 2c7568204000683a434b1c22ebbe16b7531188f7 Mon Sep 17 00:00:00 2001 From: Kudlaty <kfuks2@gmail.com> Date: Wed, 6 May 2020 07:23:41 +0200 Subject: [PATCH 107/427] docs(tutorials/github_actions): fix workflow to not skip commits with bump word --- 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 234c4cc50d..683a8a9de9 100644 --- a/docs/tutorials/github_actions.md +++ b/docs/tutorials/github_actions.md @@ -20,7 +20,7 @@ on: jobs: build: - if: "!contains(github.event.head_commit.message, 'bump')" + if: "!startsWith(github.event.head_commit.message, 'bump:')" runs-on: ubuntu-latest strategy: matrix: From efdc6c5ea0750d8a4242b97913b4b0f891ffc711 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 6 May 2020 07:24:50 +0000 Subject: [PATCH 108/427] =?UTF-8?q?bump:=20version=201.19.3=20=E2=86=92=20?= =?UTF-8?q?1.20.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 7 +++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96908a7b9e..bfc4b0da68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ + +## v1.20.0 (2020-05-06) + +### Feat + +- **bump**: add optional --no-verify argument for bump command + ## v1.19.3 (2020-05-04) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index f27cba7c78..0dcddbc87b 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.19.3" +__version__ = "1.20.0" diff --git a/pyproject.toml b/pyproject.toml index c913ecad8d..85d852c745 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.19.3" +version = "1.20.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.19.3" +version = "1.20.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 994ceb957ccb1e324b03acc76fe3ec8af2c80385 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 9 May 2020 12:24:51 +0800 Subject: [PATCH 109/427] feat(commands/bump): add "--check-consistency" optional check whether the versions defined in commitizen config and version file are consistent --- commitizen/bump.py | 41 +++++++--- commitizen/changelog.py | 6 +- commitizen/cli.py | 8 ++ commitizen/commands/bump.py | 10 ++- commitizen/error_codes.py | 1 + tests/commands/test_bump_command.py | 28 ++++++- tests/conftest.py | 10 ++- tests/test_bump_update_version_in_files.py | 87 +++++++++++++++------- tests/test_changelog_parser.py | 12 +-- 9 files changed, 144 insertions(+), 59 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index 171accbd44..ff99c3d427 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -6,6 +6,7 @@ from packaging.version import Version +from commitizen import out from commitizen.defaults import ( MAJOR, MINOR, @@ -14,6 +15,7 @@ bump_message, bump_pattern, ) +from commitizen.error_codes import CURRENT_VERSION_NOT_FOUND from commitizen.git import GitCommit @@ -126,34 +128,49 @@ def generate_version( return Version(f"{semver}{pre_version}") -def update_version_in_files(current_version: str, new_version: str, files: list): +def update_version_in_files( + current_version: str, new_version: str, files: List[str], *, check_consistency=False +): """Change old version to the new one in every file given. Note that this version is not the tag formatted one. So for example, your tag could look like `v1.0.0` while your version in the package like `1.0.0`. """ + # TODO: sepearte check step and write step for location in files: - filepath, *regex = location.split(":", maxsplit=1) - if len(regex) > 0: - regex = regex[0] + filepath, *regexes = location.split(":", maxsplit=1) + regex = regexes[0] if regexes else None # Read in the file - filedata = [] - with open(filepath, "r") as f: - for line in f: + file_content = [] + current_version_found = False + with open(filepath, "r") as version_file: + for line in version_file: if regex: - is_match = re.search(regex, line) - if not is_match: - filedata.append(line) + match = re.search(regex, line) + if not match: + file_content.append(line) continue # Replace the target string - filedata.append(line.replace(current_version, new_version)) + if current_version in line: + current_version_found = True + file_content.append(line.replace(current_version, new_version)) + else: + file_content.append(line) + + if check_consistency and not current_version_found: + out.error( + f"Current version {current_version} is not found in {location}.\n" + "The version defined in commitizen configuration and the ones in " + "version_files are possibly inconsistent." + ) + raise SystemExit(CURRENT_VERSION_NOT_FOUND) # Write the file out again with open(filepath, "w") as file: - file.write("".join(filedata)) + file.write("".join(file_content)) def create_tag(version: Union[Version, str], tag_format: Optional[str] = None): diff --git a/commitizen/changelog.py b/commitizen/changelog.py index 099c647ece..c701f4fcd9 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -122,11 +122,7 @@ def generate_tree_from_commits( change_type = parsed_message_body.pop("change_type", None) changes[change_type].append(parsed_message_body) - yield { - "version": current_tag_name, - "date": current_tag_date, - "changes": changes, - } + yield {"version": current_tag_name, "date": current_tag_date, "changes": changes} def render_changelog(tree: Iterable) -> str: diff --git a/commitizen/cli.py b/commitizen/cli.py index 8fea00400e..3bb6f2843f 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -128,6 +128,14 @@ "help": "manually specify the desired increment", "choices": ["MAJOR", "MINOR", "PATCH"], }, + { + "name": ["--check-consistency", "-cc"], + "help": ( + "check consistency among versions defined in " + "commitizen configuration and version_files" + ), + "action": "store_true", + }, ], }, { diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 80a9a8ebcd..61d40d16eb 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -32,6 +32,7 @@ def __init__(self, config: BaseConfig, arguments: dict): self.cz = factory.commiter_factory(self.config) self.changelog = arguments["changelog"] self.no_verify = arguments["no_verify"] + self.check_consistency = arguments["check_consistency"] def is_initial_tag(self, current_tag_version: str, is_yes: bool = False) -> bool: """Check if reading the whole git tree up to HEAD is needed.""" @@ -79,7 +80,7 @@ def __call__(self): # noqa: C901 tag_format: str = self.bump_settings["tag_format"] bump_commit_message: str = self.bump_settings["bump_message"] - version_files: list = self.bump_settings["version_files"] + version_files: List[str] = self.bump_settings["version_files"] dry_run: bool = self.arguments["dry_run"] is_yes: bool = self.arguments["yes"] @@ -130,7 +131,12 @@ def __call__(self): # noqa: C901 if dry_run: raise SystemExit() - bump.update_version_in_files(current_version, new_version.public, version_files) + bump.update_version_in_files( + current_version, + new_version.public, + version_files, + check_consistency=self.check_consistency, + ) if is_files_only: raise SystemExit() diff --git a/commitizen/error_codes.py b/commitizen/error_codes.py index 9095399c3f..fa928e769d 100644 --- a/commitizen/error_codes.py +++ b/commitizen/error_codes.py @@ -11,6 +11,7 @@ NO_PATTERN_MAP = 5 COMMIT_FAILED = 6 TAG_FAILED = 7 +CURRENT_VERSION_NOT_FOUND = 17 # Commit NO_ANSWERS = 8 diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index 5ce0228d36..84f26db42d 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -3,6 +3,7 @@ import pytest from commitizen import cli, cmd, git +from commitizen.error_codes import CURRENT_VERSION_NOT_FOUND from tests.utils import create_file_and_commit @@ -135,7 +136,7 @@ def test_bump_is_not_specify(mocker, capsys): @pytest.mark.usefixtures("tmp_commitizen_project") -def test_bump_when_not_new_commit(mocker, capsys): +def test_bump_when_no_new_commit(mocker, capsys): testargs = ["cz", "bump", "--yes"] mocker.patch.object(sys, "argv", testargs) @@ -145,3 +146,28 @@ def test_bump_when_not_new_commit(mocker, capsys): expected_error_message = "[NO_COMMITS_FOUND]\n" "No new commits found." _, err = capsys.readouterr() assert expected_error_message in err + + +def test_bump_when_version_inconsistent_in_version_files( + tmp_commitizen_project, mocker, capsys +): + tmp_version_file = tmp_commitizen_project.join("__version__.py") + tmp_version_file.write("100.999.10000") + tmp_commitizen_cfg_file = tmp_commitizen_project.join("pyproject.toml") + tmp_commitizen_cfg_file.write( + f"{tmp_commitizen_cfg_file.read()}\n" + f'version_files = ["{str(tmp_version_file)}"]' + ) + + create_file_and_commit("feat: new file") + + testargs = ["cz", "bump", "--yes", "--check-consistency"] + mocker.patch.object(sys, "argv", testargs) + + with pytest.raises(SystemExit) as excinfo: + cli.main() + + partial_expected_error_message = "Current version 0.1.0 is not found in" + _, err = capsys.readouterr() + assert excinfo.value.code == CURRENT_VERSION_NOT_FOUND + assert partial_expected_error_message in err diff --git a/tests/conftest.py b/tests/conftest.py index 5d1acdcdfd..f293d5631b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -8,11 +8,13 @@ def tmp_git_project(tmpdir): with tmpdir.as_cwd(): cmd.run("git init") - yield + yield tmpdir @pytest.fixture(scope="function") -@pytest.mark.usefixtures("tmp_git_project") def tmp_commitizen_project(tmp_git_project): - with open("pyproject.toml", "w") as f: - f.write("[tool.commitizen]\n" 'version="0.1.0"') + with tmp_git_project.as_cwd(): + tmp_commitizen_cfg_file = tmp_git_project.join("pyproject.toml") + tmp_commitizen_cfg_file.write("[tool.commitizen]\n" 'version="0.1.0"\n') + + yield tmp_git_project diff --git a/tests/test_bump_update_version_in_files.py b/tests/test_bump_update_version_in_files.py index e94c5544c4..4b48b0326c 100644 --- a/tests/test_bump_update_version_in_files.py +++ b/tests/test_bump_update_version_in_files.py @@ -1,8 +1,7 @@ -import os - import pytest from commitizen import bump +from commitizen.error_codes import CURRENT_VERSION_NOT_FOUND PYPROJECT = """ [tool.poetry] @@ -17,6 +16,13 @@ __version__ = '1.2.3' """ +INCONSISTENT_VERSION_PY = """ +__title__ = 'requests' +__description__ = 'Python HTTP for Humans.' +__url__ = 'http://python-requests.org' +__version__ = '2.10.3' +""" + REPEATED_VERSION_NUMBER = """ { "name": "magictool", @@ -27,46 +33,75 @@ } """ -files_with_content = ( - ("pyproject.toml", PYPROJECT), - ("__version__.py", VERSION_PY), - ("package.json", REPEATED_VERSION_NUMBER), -) + +@pytest.fixture(scope="function") +def commitizen_config_file(tmpdir): + tmp_file = tmpdir.join("pyproject.toml") + tmp_file.write(PYPROJECT) + return str(tmp_file) + + +@pytest.fixture(scope="function") +def python_version_file(tmpdir): + tmp_file = tmpdir.join("__verion__.py") + tmp_file.write(VERSION_PY) + return str(tmp_file) -@pytest.fixture -def create_files(): - files = [] - for fileconf in files_with_content: - filename, content = fileconf - filepath = os.path.join("tests", filename) - with open(filepath, "w") as f: - f.write(content) - files.append(filepath) - yield files - for filepath in files: - os.remove(filepath) +@pytest.fixture(scope="function") +def inconsistent_python_version_file(tmpdir): + tmp_file = tmpdir.join("__verion__.py") + tmp_file.write(INCONSISTENT_VERSION_PY) + return str(tmp_file) -def test_update_version_in_files(create_files): +@pytest.fixture(scope="function") +def version_repeated_file(tmpdir): + tmp_file = tmpdir.join("package.json") + tmp_file.write(REPEATED_VERSION_NUMBER) + return str(tmp_file) + + +@pytest.fixture(scope="function") +def version_files(commitizen_config_file, python_version_file, version_repeated_file): + return [commitizen_config_file, python_version_file, version_repeated_file] + + +def test_update_version_in_files(version_files): old_version = "1.2.3" new_version = "2.0.0" - bump.update_version_in_files(old_version, new_version, create_files) - for filepath in create_files: + bump.update_version_in_files(old_version, new_version, version_files) + for filepath in version_files: with open(filepath, "r") as f: data = f.read() assert new_version in data -def test_partial_update_of_file(create_files): +def test_partial_update_of_file(version_repeated_file): old_version = "1.2.3" new_version = "2.0.0" - filepath = "tests/package.json" regex = "version" - location = f"{filepath}:{regex}" + location = f"{version_repeated_file}:{regex}" bump.update_version_in_files(old_version, new_version, [location]) - with open(filepath, "r") as f: + with open(version_repeated_file, "r") as f: data = f.read() assert new_version in data assert old_version in data + + +def test_file_version_inconsistent_error( + commitizen_config_file, inconsistent_python_version_file, version_repeated_file +): + version_files = [ + commitizen_config_file, + inconsistent_python_version_file, + version_repeated_file, + ] + old_version = "1.2.3" + new_version = "2.0.0" + with pytest.raises(SystemExit) as excinfo: + bump.update_version_in_files( + old_version, new_version, version_files, check_consistency=True + ) + assert excinfo.value.code == CURRENT_VERSION_NOT_FOUND diff --git a/tests/test_changelog_parser.py b/tests/test_changelog_parser.py index f07d8c3f63..438b2f766d 100644 --- a/tests/test_changelog_parser.py +++ b/tests/test_changelog_parser.py @@ -167,27 +167,21 @@ def test_generate_full_tree(existing_changelog_file): "message": "issue in poetry add preventing the installation in py36", "breaking": None, }, - { - "scope": "users", - "message": "lorem ipsum apap", - "breaking": None, - }, + {"scope": "users", "message": "lorem ipsum apap", "breaking": None}, ], "feat": [ { "scope": None, "message": "it is possible to specify a pattern to be matched in configuration files bump.", "breaking": None, - }, + } ], }, "version": "1.0.0", "date": "2019-07-12", }, { - "changes": { - "fix": [{"scope": None, "message": "holis", "breaking": None}], - }, + "changes": {"fix": [{"scope": None, "message": "holis", "breaking": None}]}, "version": "0.9", "date": "2019-07-11", }, From f14670dbaef8ff4ae8e0b0d3bcae6f3089218dd8 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 9 May 2020 16:43:53 +0800 Subject: [PATCH 110/427] docs(bump): update for --check-consistency argument --- docs/bump.md | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/docs/bump.md b/docs/bump.md index a70c35d303..a50c502afd 100644 --- a/docs/bump.md +++ b/docs/bump.md @@ -54,17 +54,18 @@ Some examples: ```bash $ cz bump --help -usage: cz bump [-h] [--dry-run] [--files-only] [--changelog] [--no-verify] [--yes] - [--tag-format TAG_FORMAT] [--bump-message BUMP_MESSAGE] +usage: cz bump [-h] [--dry-run] [--files-only] [--changelog] [--no-verify] + [--yes] [--tag-format TAG_FORMAT] [--bump-message BUMP_MESSAGE] [--prerelease {alpha,beta,rc}] - [--increment {MAJOR,MINOR,PATCH}] + [--increment {MAJOR,MINOR,PATCH}] [--check-consistency] 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 --changelog, -ch generate the changelog for the newest version - --no-verify this option bypasses the pre-commit and commit-msg hooks + --no-verify this option bypasses the pre-commit and commit-msg + hooks --yes accept automatically questions done --tag-format TAG_FORMAT the format used to tag the commit and read it, use it @@ -76,11 +77,12 @@ optional arguments: choose type of prerelease --increment {MAJOR,MINOR,PATCH} manually specify the desired increment + --check-consistency, -cc + check consistency among versions defined in commitizen + configuration and version_files ``` -## Configuration - -### `changelog` +### `--changelog` Generate a **changelog** along with the new version and tag when bumping. @@ -88,6 +90,17 @@ Generate a **changelog** along with the new version and tag when bumping. cz bump --changelog ``` +### `--check-consistency` + +Check whether the versions defined in `version_files` and the version in commitizen +configuration are consistent before bumping version. + +```bash +cz bump --check-consistency +``` + +## Configuration + ### `tag_format` It is used to read the format from the git tags, and also to generate the tags. From b3488287af7f9b6aea184c349f6e9d01c55f1995 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 9 May 2020 16:53:00 +0800 Subject: [PATCH 111/427] docs(github): add pull request template --- .github/pull_request_template.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..ceff272b01 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,10 @@ +## Related Issue + +## Detail + +## Checklist: + +- [ ] Run "./script/lint" and "./script/test" locally to ensure this change passes linter check and test +- [ ] Add test cases to all the changes +- [ ] Test the changes on the local machine manually +- [ ] Update the documentation for the changes From 7c59662b057920ffdf33a5c47b6e66a2c7f95a66 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 9 May 2020 18:38:42 +0800 Subject: [PATCH 112/427] docs(bump): add example to --check-inconsistency --- docs/bump.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/bump.md b/docs/bump.md index a50c502afd..efcef4a3b3 100644 --- a/docs/bump.md +++ b/docs/bump.md @@ -99,6 +99,39 @@ configuration are consistent before bumping version. cz bump --check-consistency ``` +For example, if we have `pyproject.toml` + +```toml +[tool.commitizen] +version = "1.21.0" +version_files = [ + "src/__version__.py", + "setup.py", +] +``` + +`src/__version__.py`, + +```python +__version__ = "1.21.0" +``` + +and `setup.py`. + +```python +... + version="1.0.5" +... +``` + +If `--check-consistency` is used, commitizen will check whether the current version in `pyproject.toml` +exists in all version_files and find out it does not exist in `setup.py` and fails. +However, it will still update `pyproject.toml` and `src/__version__.py`. + +To fix it, you'll first `git checkout .` to reset to the status before trying to bump and update +the version in `setup.py` to `1.21.0` + + ## Configuration ### `tag_format` From 47cc71287d78f496a7d2cb9073e8151e8583740c Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sat, 9 May 2020 10:45:24 +0000 Subject: [PATCH 113/427] =?UTF-8?q?bump:=20version=201.20.0=20=E2=86=92=20?= =?UTF-8?q?1.21.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 7 +++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfc4b0da68..44a2287b8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ + +## v1.21.0 (2020-05-09) + +### Feat + +- **commands/bump**: add "--check-consistency" optional + ## v1.20.0 (2020-05-06) ### Feat diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 0dcddbc87b..6df86cae31 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.20.0" +__version__ = "1.21.0" diff --git a/pyproject.toml b/pyproject.toml index 85d852c745..327cb049ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.20.0" +version = "1.21.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.20.0" +version = "1.21.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 5b9837b9ba47a60e42807c150fa9db9a5b17714b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Tue, 12 May 2020 17:13:43 +0200 Subject: [PATCH 114/427] feat(changelog): add support for modifying the change_type in the title of the changelog --- commitizen/changelog.py | 5 ++- commitizen/commands/changelog.py | 13 +++++- commitizen/cz/base.py | 2 +- .../conventional_commits.py | 6 +++ .../templates/keep_a_changelog_template.j2 | 2 +- tests/CHANGELOG_FOR_TEST.md | 42 +++++++++---------- tests/test_changelog.py | 12 ++++++ 7 files changed, 56 insertions(+), 26 deletions(-) diff --git a/commitizen/changelog.py b/commitizen/changelog.py index c701f4fcd9..bd3c0b1d6a 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -72,6 +72,7 @@ def generate_tree_from_commits( commit_parser: str, changelog_pattern: str = defaults.bump_pattern, unreleased_version: Optional[str] = None, + change_type_map: Optional[Dict[str, str]] = None, ) -> Iterable[Dict]: pat = re.compile(changelog_pattern) map_pat = re.compile(commit_parser) @@ -112,10 +113,12 @@ def generate_tree_from_commits( message = map_pat.match(commit.message) message_body = map_pat.match(commit.body) if message: - # TODO: add a post hook coming from a rule (CzBase) parsed_message: Dict = message.groupdict() # change_type becomes optional by providing None change_type = parsed_message.pop("change_type", None) + + if change_type_map: + change_type = change_type_map.get(change_type, change_type) changes[change_type].append(parsed_message) if message_body: parsed_message_body: Dict = message_body.groupdict() diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 0d6f8bb426..6ce8e0d0b3 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -1,7 +1,7 @@ import os.path from difflib import SequenceMatcher from operator import itemgetter -from typing import Dict, List +from typing import Dict, List, Optional from commitizen import changelog, factory, git, out from commitizen.config import BaseConfig @@ -27,6 +27,9 @@ def __init__(self, config: BaseConfig, args): self.incremental = args["incremental"] self.dry_run = args["dry_run"] self.unreleased_version = args["unreleased_version"] + self.change_type_map = ( + self.config.settings.get("change_type_map") or self.cz.change_type_map + ) def _find_incremental_rev(self, latest_version: str, tags: List[GitTag]) -> str: """Try to find the 'start_rev'. @@ -60,6 +63,7 @@ def __call__(self): start_rev = self.start_rev unreleased_version = self.unreleased_version changelog_meta: Dict = {} + change_type_map: Optional[Dict] = self.change_type_map if not changelog_pattern or not commit_parser: out.error( @@ -83,7 +87,12 @@ def __call__(self): raise SystemExit(NO_COMMITS_FOUND) tree = changelog.generate_tree_from_commits( - commits, tags, commit_parser, changelog_pattern, unreleased_version + commits, + tags, + commit_parser, + changelog_pattern, + unreleased_version, + change_type_map, ) changelog_out = changelog.render_changelog(tree) diff --git a/commitizen/cz/base.py b/commitizen/cz/base.py index c6e74d95b0..3d129f638c 100644 --- a/commitizen/cz/base.py +++ b/commitizen/cz/base.py @@ -27,7 +27,7 @@ class BaseCommitizen(metaclass=ABCMeta): # It can be modified per rule commit_parser: Optional[str] = r"(?P<message>.*)" changelog_pattern: Optional[str] = r".*" - changelog_map: Optional[dict] = None # TODO: Use it + change_type_map: Optional[dict] = None def __init__(self, config: BaseConfig): self.config = config diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index b932bd6682..e3fbb8c269 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -32,6 +32,12 @@ class ConventionalCommitsCz(BaseCommitizen): bump_map = defaults.bump_map commit_parser = defaults.commit_parser changelog_pattern = defaults.bump_pattern + change_type_map = { + "feat": "Feat", + "fix": "Fix", + "refactor": "Refactor", + "perf": "Perf", + } def questions(self) -> List[Dict[str, Any]]: questions: List[Dict[str, Any]] = [ diff --git a/commitizen/templates/keep_a_changelog_template.j2 b/commitizen/templates/keep_a_changelog_template.j2 index be0d0d26e6..381fe88bf3 100644 --- a/commitizen/templates/keep_a_changelog_template.j2 +++ b/commitizen/templates/keep_a_changelog_template.j2 @@ -5,7 +5,7 @@ {% for change_key, changes in entry.changes.items() %} {% if change_key %} -### {{ change_key|title }} +### {{ change_key }} {% endif %} {% for change in changes %} diff --git a/tests/CHANGELOG_FOR_TEST.md b/tests/CHANGELOG_FOR_TEST.md index 7605bbed47..798b07545a 100644 --- a/tests/CHANGELOG_FOR_TEST.md +++ b/tests/CHANGELOG_FOR_TEST.md @@ -1,13 +1,13 @@ ## v1.2.0 (2019-04-19) -### Feat +### feat - custom cz plugins now support bumping version ## v1.1.1 (2019-04-18) -### Refactor +### refactor - changed stdout statements - **schema**: command logic removed from commitizen base @@ -15,14 +15,14 @@ - **example**: command logic removed from commitizen base - **commit**: moved most of the commit logic to the commit command -### Fix +### fix - **bump**: commit message now fits better with semver - conventional commit 'breaking change' in body instead of title ## v1.1.0 (2019-04-14) -### Feat +### feat - new working bump command - create version tag @@ -31,22 +31,22 @@ - support for pyproject.toml - first semantic version bump implementaiton -### Fix +### fix - removed all from commit - fix config file not working -### Refactor +### refactor - added commands folder, better integration with decli ## v1.0.0 (2019-03-01) -### Refactor +### refactor - removed delegator, added decli and many tests -### Breaking Change +### BREAKING CHANGE - API is stable @@ -54,76 +54,76 @@ ## v1.0.0b1 (2019-01-17) -### Feat +### feat - py3 only, tests and conventional commits 1.0 ## v0.9.11 (2018-12-17) -### Fix +### fix - **config**: load config reads in order without failing if there is no commitizen section ## v0.9.10 (2018-09-22) -### Fix +### fix - parse scope (this is my punishment for not having tests) ## v0.9.9 (2018-09-22) -### Fix +### fix - parse scope empty ## v0.9.8 (2018-09-22) -### Fix +### fix - **scope**: parse correctly again ## v0.9.7 (2018-09-22) -### Fix +### fix - **scope**: parse correctly ## v0.9.6 (2018-09-19) -### Refactor +### refactor - **conventionalCommit**: moved fitlers to questions instead of message -### Fix +### fix - **manifest**: inluded missing files ## v0.9.5 (2018-08-24) -### Fix +### fix - **config**: home path for python versions between 3.0 and 3.5 ## v0.9.4 (2018-08-02) -### Feat +### feat - **cli**: added version ## v0.9.3 (2018-07-28) -### Feat +### feat - **commiter**: conventional commit is a bit more intelligent now ## v0.9.2 (2017-11-11) -### Refactor +### refactor - renamed conventional_changelog to conventional_commits, not backward compatible ## v0.9.1 (2017-11-11) -### Fix +### fix - **setup.py**: future is now required for every python version diff --git a/tests/test_changelog.py b/tests/test_changelog.py index 94c3c47017..dace772e8f 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -701,3 +701,15 @@ def test_render_changelog_tag_and_unreleased(gitcommits, tags): assert "Unreleased" in result assert "## v1.1.1" in result + + +def test_render_changelog_with_change_type(gitcommits, tags, changelog_content): + new_title = ":some-emoji: feature" + change_type_map = {"feat": new_title} + parser = defaults.commit_parser + changelog_pattern = defaults.bump_pattern + tree = changelog.generate_tree_from_commits( + gitcommits, tags, parser, changelog_pattern, change_type_map=change_type_map + ) + result = changelog.render_changelog(tree) + assert new_title in result From 141981bb1bb14db50b6b3b5625a8b4c1ecd9ba4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Tue, 12 May 2020 17:14:04 +0200 Subject: [PATCH 115/427] docs: add info about creating custom changelog --- docs/changelog.md | 2 +- docs/customization.md | 61 +++++++++++++++++++++++++++---------------- 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index fab38ea2ad..a5eaa5d343 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -127,7 +127,7 @@ cz changelog --incremental ## TODO - [ ] support for hooks: this would allow introduction of custom information in the commiter, like a github or jira url. Eventually we could build a `CzConventionalGithub`, which would add links to commits -- [ ] support for map: allow the usage of a `change_type` mapper, to convert from feat to feature for example. +- [x] support for map: allow the usage of a `change_type` mapper, to convert from feat to feature for example. [keepachangelog]: https://keepachangelog.com/ [semver]: https://semver.org/ diff --git a/docs/customization.md b/docs/customization.md index bae9f047af..2d9bcf5f27 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -106,12 +106,12 @@ If you feel like it should be part of this repo, create a PR. ### Custom bump rules -You need to define 2 parameters inside `BaseCommitizen`. +You need to define 2 parameters inside your custom `BaseCommitizen`. -| Parameter | Type | Default | Description | -| --------- | ---- | ------- | ----------- | -| `bump_pattern` | `str` | `None` | Regex to extract information from commit (subject and body) | -| `bump_map` | `dict` | `None` | Dictionary mapping the extracted information to a `SemVer` increment type (`MAJOR`, `MINOR`, `PATCH`) | +| Parameter | Type | Default | Description | +| -------------- | ------ | ------- | ----------------------------------------------------------------------------------------------------- | +| `bump_pattern` | `str` | `None` | Regex to extract information from commit (subject and body) | +| `bump_map` | `dict` | `None` | Dictionary mapping the extracted information to a `SemVer` increment type (`MAJOR`, `MINOR`, `PATCH`) | Let's see an example. @@ -132,6 +132,20 @@ cz -n cz_strange bump [convcomms]: https://github.com/commitizen-tools/commitizen/blob/master/commitizen/cz/conventional_commits/conventional_commits.py +## Custom changelog generator + +The changelog generator should just work in a very basic manner without touching anything. +You can customize it of course, and this are the variables you need to add to your custom `BaseCommitizen`. + +| Parameter | Type | Required | Description | +| ------------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| `commit_parser` | `str` | NO | Regex which should provide the variables explained in the [changelog description][changelog-des] | +| `changelog_pattern` | `str` | NO | Regex to validate the commits, this is useful to skip commits that don't meet your rulling standards like a Merge. Usually the same as bump_pattern | +| `change_type_map` | `dict` | NO | Convert the title of the change type that will appear in the changelog, if a value is not found, the original will be provided | + + +[changelog-des]: ./changelog.md#description + ### Raise Customize Exception If you want `commitizen` to catch your exception and print the message, you'll have to inherit `CzException`. @@ -148,6 +162,7 @@ class NoSubjectProvidedException(CzException): **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 bumping rules in the configuration file. 2. Declare `name = "cz_customize"` in your configuration file, or add `-n cz_customize` when running commitizen. @@ -187,24 +202,24 @@ message = "Do you want to add body message in commit?" ### Customize configuration -| Parameter | Type | Default | Description | -| --------- | ---- | ------- | ----------- | -| `question` | `dict` | `None` | Questions regarding the commit message. Detailed below. | -| `message_template` | `str` | `None` | The template for generating message from the given answers. `message_template` should either follow 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. | -| `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) | +| Parameter | Type | Default | Description | +| ------------------ | ------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `question` | `dict` | `None` | Questions regarding the commit message. Detailed below. | +| `message_template` | `str` | `None` | The template for generating message from the given answers. `message_template` should either follow 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. | +| `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)** | +| 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 e8b7ab1ce86037439d45f40bee12645cd4260bed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Tue, 12 May 2020 17:32:37 +0200 Subject: [PATCH 116/427] feat(changelog): add support for `message_hook` method --- commitizen/changelog.py | 5 ++++- commitizen/commands/changelog.py | 6 ++++-- commitizen/cz/base.py | 3 ++- tests/test_changelog.py | 16 +++++++++++++++- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/commitizen/changelog.py b/commitizen/changelog.py index bd3c0b1d6a..8103116b56 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -29,7 +29,7 @@ import re from collections import defaultdict from datetime import date -from typing import Dict, Iterable, List, Optional +from typing import Callable, Dict, Iterable, List, Optional import pkg_resources from jinja2 import Template @@ -73,6 +73,7 @@ def generate_tree_from_commits( changelog_pattern: str = defaults.bump_pattern, unreleased_version: Optional[str] = None, change_type_map: Optional[Dict[str, str]] = None, + message_hook: Optional[Callable] = None, ) -> Iterable[Dict]: pat = re.compile(changelog_pattern) map_pat = re.compile(commit_parser) @@ -119,6 +120,8 @@ def generate_tree_from_commits( if change_type_map: change_type = change_type_map.get(change_type, change_type) + if message_hook: + parsed_message = message_hook(parsed_message, commit) changes[change_type].append(parsed_message) if message_body: parsed_message_body: Dict = message_body.groupdict() diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 6ce8e0d0b3..36799aff09 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -1,7 +1,7 @@ import os.path from difflib import SequenceMatcher from operator import itemgetter -from typing import Dict, List, Optional +from typing import Callable, Dict, List, Optional from commitizen import changelog, factory, git, out from commitizen.config import BaseConfig @@ -64,6 +64,7 @@ def __call__(self): unreleased_version = self.unreleased_version changelog_meta: Dict = {} change_type_map: Optional[Dict] = self.change_type_map + message_hook: Optional[Callable] = self.cz.message_hook if not changelog_pattern or not commit_parser: out.error( @@ -92,7 +93,8 @@ def __call__(self): commit_parser, changelog_pattern, unreleased_version, - change_type_map, + change_type_map=change_type_map, + message_hook=message_hook, ) changelog_out = changelog.render_changelog(tree) diff --git a/commitizen/cz/base.py b/commitizen/cz/base.py index 3d129f638c..435cb34e2d 100644 --- a/commitizen/cz/base.py +++ b/commitizen/cz/base.py @@ -1,5 +1,5 @@ from abc import ABCMeta, abstractmethod -from typing import List, Optional, Tuple +from typing import Callable, List, Optional, Tuple from prompt_toolkit.styles import Style, merge_styles @@ -28,6 +28,7 @@ class BaseCommitizen(metaclass=ABCMeta): commit_parser: Optional[str] = r"(?P<message>.*)" changelog_pattern: Optional[str] = r".*" change_type_map: Optional[dict] = None + message_hook: Optional[Callable] = None # (dict, GitCommit) -> dict def __init__(self, config: BaseConfig): self.config = config diff --git a/tests/test_changelog.py b/tests/test_changelog.py index dace772e8f..0a11810ecb 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -703,7 +703,7 @@ def test_render_changelog_tag_and_unreleased(gitcommits, tags): assert "## v1.1.1" in result -def test_render_changelog_with_change_type(gitcommits, tags, changelog_content): +def test_render_changelog_with_change_type(gitcommits, tags): new_title = ":some-emoji: feature" change_type_map = {"feat": new_title} parser = defaults.commit_parser @@ -713,3 +713,17 @@ def test_render_changelog_with_change_type(gitcommits, tags, changelog_content): ) result = changelog.render_changelog(tree) assert new_title in result + + +def test_render_changelog_with_message_hook(gitcommits, tags): + def message_hook(message: dict, _) -> dict: + message["message"] = f"{message['message']} [link](github.com/232323232)" + return message + + parser = defaults.commit_parser + changelog_pattern = defaults.bump_pattern + tree = changelog.generate_tree_from_commits( + gitcommits, tags, parser, changelog_pattern, message_hook=message_hook + ) + result = changelog.render_changelog(tree) + assert "[link](github.com/232323232)" in result From 221a8d75a539063ca73d095f6f475d32aa8b9a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Tue, 12 May 2020 17:33:20 +0200 Subject: [PATCH 117/427] docs(changelog): document usage of message_hook --- docs/customization.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/customization.md b/docs/customization.md index 2d9bcf5f27..8566db06e7 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -137,12 +137,12 @@ cz -n cz_strange bump The changelog generator should just work in a very basic manner without touching anything. You can customize it of course, and this are the variables you need to add to your custom `BaseCommitizen`. -| Parameter | Type | Required | Description | -| ------------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| `commit_parser` | `str` | NO | Regex which should provide the variables explained in the [changelog description][changelog-des] | -| `changelog_pattern` | `str` | NO | Regex to validate the commits, this is useful to skip commits that don't meet your rulling standards like a Merge. Usually the same as bump_pattern | -| `change_type_map` | `dict` | NO | Convert the title of the change type that will appear in the changelog, if a value is not found, the original will be provided | - +| Parameter | Type | Required | Description | +| ------------------- | --------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| `commit_parser` | `str` | NO | Regex which should provide the variables explained in the [changelog description][changelog-des] | +| `changelog_pattern` | `str` | NO | Regex to validate the commits, this is useful to skip commits that don't meet your rulling standards like a Merge. Usually the same as bump_pattern | +| `change_type_map` | `dict` | NO | Convert the title of the change type that will appear in the changelog, if a value is not found, the original will be provided | +| `message_hook` | `method: (dict, git.GitCommit) -> dict` | NO | Customize with extra information your message output, like adding links, this function is executed per parsed commit. | [changelog-des]: ./changelog.md#description From 87bebaf00c405683d5a243ecc0d38481184ade75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Tue, 12 May 2020 18:25:41 +0200 Subject: [PATCH 118/427] feat(changelog): add support for `changelog_hook` when changelog finishes the generation --- commitizen/commands/changelog.py | 11 ++++++++--- commitizen/cz/base.py | 12 +++++++++--- setup.cfg | 2 +- tests/commands/test_changelog_command.py | 20 ++++++++++++++++++++ 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 36799aff09..50564bb4ae 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -65,6 +65,7 @@ def __call__(self): changelog_meta: Dict = {} change_type_map: Optional[Dict] = self.change_type_map message_hook: Optional[Callable] = self.cz.message_hook + changelog_hook: Optional[Callable] = self.cz.changelog_hook if not changelog_pattern or not commit_parser: out.error( @@ -108,10 +109,14 @@ def __call__(self): lines = changelog_file.readlines() with open(self.file_name, "w") as changelog_file: + partial_changelog: Optional[str] = None if self.incremental: new_lines = changelog.incremental_build( changelog_out, lines, changelog_meta ) - changelog_file.writelines(new_lines) - else: - changelog_file.write(changelog_out) + changelog_out = "".join(new_lines) + partial_changelog = changelog_out + + if changelog_hook: + changelog_out = changelog_hook(changelog_out, partial_changelog) + changelog_file.write(changelog_out) diff --git a/commitizen/cz/base.py b/commitizen/cz/base.py index 435cb34e2d..8c3a082189 100644 --- a/commitizen/cz/base.py +++ b/commitizen/cz/base.py @@ -1,8 +1,9 @@ from abc import ABCMeta, abstractmethod -from typing import Callable, List, Optional, Tuple +from typing import Callable, Dict, List, Optional, Tuple from prompt_toolkit.styles import Style, merge_styles +from commitizen import git from commitizen.config.base_config import BaseConfig @@ -27,8 +28,13 @@ class BaseCommitizen(metaclass=ABCMeta): # It can be modified per rule commit_parser: Optional[str] = r"(?P<message>.*)" changelog_pattern: Optional[str] = r".*" - change_type_map: Optional[dict] = None - message_hook: Optional[Callable] = None # (dict, GitCommit) -> dict + change_type_map: Optional[Dict[str, str]] = None + + # Executed per message parsed by the commitizen + message_hook: Optional[Callable[[Dict, git.GitCommit], Dict]] = None + + # Executed only at the end of the changelog generation + changelog_hook: Optional[Callable[[str, Optional[str]], str]] = None def __init__(self, config: BaseConfig): self.config = config diff --git a/setup.cfg b/setup.cfg index ac1f11ee38..de0172c175 100644 --- a/setup.cfg +++ b/setup.cfg @@ -35,4 +35,4 @@ exclude = build, dist max-line-length = 88 -max-complexity = 10 +max-complexity = 11 diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index d78d04bee2..0c7982ea6c 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -5,6 +5,7 @@ import pytest from commitizen import cli, git +from commitizen.commands.changelog import Changelog from tests.utils import create_file_and_commit @@ -234,3 +235,22 @@ def test_changlog_incremental_keep_a_changelog_sample(mocker, capsys): out == """# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n\n## Unreleased \n\n### Feat\n\n- add more stuff\n- add new output\n\n### Fix\n\n- mama gotta work\n- output glitch\n\n## [1.0.0] - 2017-06-20\n### Added\n- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).\n- Version navigation.\n\n### Changed\n- Start using "changelog" over "change log" since it\'s the common usage.\n\n### Removed\n- Section about "changelog" vs "CHANGELOG".\n\n## [0.3.0] - 2015-12-03\n### Added\n- RU translation from [@aishek](https://github.com/aishek).\n""" ) + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_changlog_hook(mocker, config): + changelog_hook_mock = mocker.Mock() + changelog_hook_mock.return_value = "cool changelog hook" + + create_file_and_commit("feat: new file") + create_file_and_commit("refactor: is in changelog") + create_file_and_commit("Merge into master") + + changelog = Changelog( + config, {"unreleased_version": None, "incremental": True, "dry_run": False,}, + ) + mocker.patch.object(changelog.cz, "changelog_hook", changelog_hook_mock) + changelog() + full_changelog = "\n## Unreleased \n\n### Refactor\n\n- is in changelog\n\n### Feat\n\n- new file\n" + + changelog_hook_mock.assert_called_with(full_changelog, full_changelog) From fb73367393c05f9ed34c4bf4683fcf38e6818a5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Tue, 12 May 2020 18:26:08 +0200 Subject: [PATCH 119/427] docs: add info about creating hooks --- docs/changelog.md | 11 +++-- docs/customization.md | 52 +++++++++++++++++++++--- tests/commands/test_changelog_command.py | 2 +- 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index a5eaa5d343..2c78761324 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -124,10 +124,15 @@ Benefits: cz changelog --incremental ``` -## TODO +## Hooks -- [ ] support for hooks: this would allow introduction of custom information in the commiter, like a github or jira url. Eventually we could build a `CzConventionalGithub`, which would add links to commits -- [x] support for map: allow the usage of a `change_type` mapper, to convert from feat to feature for example. +Supported hook methods: + +- per parsed message: useful to add links +- end of changelog generation: useful to send slack or chat message, or notify another department + +Read more about hooks in the [customization page][customization] [keepachangelog]: https://keepachangelog.com/ [semver]: https://semver.org/ +[customization]: ./customization.md diff --git a/docs/customization.md b/docs/customization.md index 8566db06e7..860101cb5c 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -137,12 +137,52 @@ cz -n cz_strange bump The changelog generator should just work in a very basic manner without touching anything. You can customize it of course, and this are the variables you need to add to your custom `BaseCommitizen`. -| Parameter | Type | Required | Description | -| ------------------- | --------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| `commit_parser` | `str` | NO | Regex which should provide the variables explained in the [changelog description][changelog-des] | -| `changelog_pattern` | `str` | NO | Regex to validate the commits, this is useful to skip commits that don't meet your rulling standards like a Merge. Usually the same as bump_pattern | -| `change_type_map` | `dict` | NO | Convert the title of the change type that will appear in the changelog, if a value is not found, the original will be provided | -| `message_hook` | `method: (dict, git.GitCommit) -> dict` | NO | Customize with extra information your message output, like adding links, this function is executed per parsed commit. | +| Parameter | Type | Required | Description | +| ------------------- | ------------------------------------------------------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `commit_parser` | `str` | NO | Regex which should provide the variables explained in the [changelog description][changelog-des] | +| `changelog_pattern` | `str` | NO | Regex to validate the commits, this is useful to skip commits that don't meet your rulling standards like a Merge. Usually the same as bump_pattern | +| `change_type_map` | `dict` | NO | Convert the title of the change type that will appear in the changelog, if a value is not found, the original will be provided | +| `message_hook` | `method: (dict, git.GitCommit) -> dict` | NO | Customize with extra information your message output, like adding links, this function is executed per parsed commit. | +| `changelog_hook` | `method: (full_changelog: str, partial_changelog: Optional[str]) -> str` | NO | Receives the whole and partial (if used incremental) changelog. Useful to send slack messages or notify a compliance department. Must return the full_changelog | + +```python +from commitizen.cz.base import BaseCommitizen +import chat +import compliance + +class StrangeCommitizen(BaseCommitizen): + changelog_pattern = r"^(break|new|fix|hotfix)" + commit_parser = r"^(?P<change_type>feat|fix|refactor|perf|BREAKING CHANGE)(?:\((?P<scope>[^()\r\n]*)\)|\()?(?P<breaking>!)?:\s(?P<message>.*)?" + change_type_map = { + "feat": "Features", + "fix": "Bug Fixes", + "refactor": "Code Refactor", + "perf": "Performance improvements" + } + + def message_hook(self, parsed_message: dict, commit: git.GitCommit) -> dict: + rev = commit.rev + m = parsed_message["message"] + parsed_message["message"] = f"{m} {rev}" + return parsed_message + + def changelog_hook(self, full_changelog: str, partial_changelog: Optional[str]) -> str: + """Executed at the end of the changelog generation + + full_changelog: it's the output about to being written into the file + partial_changelog: it's the new stuff, this is useful to send slack messages or + similar + + Return: + the new updated full_changelog + """ + if partial_changelog: + chat.room("#commiters").notify(partial_changelog) + if full_changelog: + compliance.send(full_changelog) + full_changelog.replace(' fix ', ' **fix** ') + return full_changelog +``` [changelog-des]: ./changelog.md#description diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index 0c7982ea6c..a676295c4c 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -247,7 +247,7 @@ def test_changlog_hook(mocker, config): create_file_and_commit("Merge into master") changelog = Changelog( - config, {"unreleased_version": None, "incremental": True, "dry_run": False,}, + config, {"unreleased_version": None, "incremental": True, "dry_run": False}, ) mocker.patch.object(changelog.cz, "changelog_hook", changelog_hook_mock) changelog() From aa2a9f9f9a11d63ef03f75a128fb504c12cad385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Tue, 12 May 2020 18:52:20 +0200 Subject: [PATCH 120/427] style: align with flake8 newest version --- commitizen/commands/version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commitizen/commands/version.py b/commitizen/commands/version.py index 344920c72a..143a0c7351 100644 --- a/commitizen/commands/version.py +++ b/commitizen/commands/version.py @@ -16,14 +16,14 @@ def __call__(self): if version: out.write(f"{version}") else: - out.error(f"No project information in this project.") + out.error("No project information in this project.") elif self.parameter.get("verbose"): out.write(f"Installed Commitizen Version: {__version__}") version = self.config.settings["version"] if version: out.write(f"Project Version: {version}") else: - out.error(f"No project information in this project.") + out.error("No project information in this project.") else: # if no argument is given, show installed commitizen version out.write(f"{__version__}") From df0042cbf236bda750c1d4b26250d16f7708f8d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Wed, 13 May 2020 12:27:53 +0200 Subject: [PATCH 121/427] fix(changelog): rename `message_hook` -> `changelog_message_builder_hook` --- commitizen/changelog.py | 6 +++--- commitizen/commands/changelog.py | 6 ++++-- commitizen/cz/base.py | 4 +++- docs/customization.md | 4 ++-- tests/test_changelog.py | 10 +++++++--- 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/commitizen/changelog.py b/commitizen/changelog.py index 8103116b56..bde2d51763 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -73,7 +73,7 @@ def generate_tree_from_commits( changelog_pattern: str = defaults.bump_pattern, unreleased_version: Optional[str] = None, change_type_map: Optional[Dict[str, str]] = None, - message_hook: Optional[Callable] = None, + changelog_message_builder_hook: Optional[Callable] = None, ) -> Iterable[Dict]: pat = re.compile(changelog_pattern) map_pat = re.compile(commit_parser) @@ -120,8 +120,8 @@ def generate_tree_from_commits( if change_type_map: change_type = change_type_map.get(change_type, change_type) - if message_hook: - parsed_message = message_hook(parsed_message, commit) + if changelog_message_builder_hook: + parsed_message = changelog_message_builder_hook(parsed_message, commit) changes[change_type].append(parsed_message) if message_body: parsed_message_body: Dict = message_body.groupdict() diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 50564bb4ae..93cd26d793 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -64,7 +64,9 @@ def __call__(self): unreleased_version = self.unreleased_version changelog_meta: Dict = {} change_type_map: Optional[Dict] = self.change_type_map - message_hook: Optional[Callable] = self.cz.message_hook + changelog_message_builder_hook: Optional[ + Callable + ] = self.cz.changelog_message_builder_hook changelog_hook: Optional[Callable] = self.cz.changelog_hook if not changelog_pattern or not commit_parser: @@ -95,7 +97,7 @@ def __call__(self): changelog_pattern, unreleased_version, change_type_map=change_type_map, - message_hook=message_hook, + changelog_message_builder_hook=changelog_message_builder_hook, ) changelog_out = changelog.render_changelog(tree) diff --git a/commitizen/cz/base.py b/commitizen/cz/base.py index 8c3a082189..ddf0c7997c 100644 --- a/commitizen/cz/base.py +++ b/commitizen/cz/base.py @@ -31,7 +31,9 @@ class BaseCommitizen(metaclass=ABCMeta): change_type_map: Optional[Dict[str, str]] = None # Executed per message parsed by the commitizen - message_hook: Optional[Callable[[Dict, git.GitCommit], Dict]] = None + changelog_message_builder_hook: Optional[ + Callable[[Dict, git.GitCommit], Dict] + ] = None # Executed only at the end of the changelog generation changelog_hook: Optional[Callable[[str, Optional[str]], str]] = None diff --git a/docs/customization.md b/docs/customization.md index 860101cb5c..721ade60b3 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -142,7 +142,7 @@ You can customize it of course, and this are the variables you need to add to yo | `commit_parser` | `str` | NO | Regex which should provide the variables explained in the [changelog description][changelog-des] | | `changelog_pattern` | `str` | NO | Regex to validate the commits, this is useful to skip commits that don't meet your rulling standards like a Merge. Usually the same as bump_pattern | | `change_type_map` | `dict` | NO | Convert the title of the change type that will appear in the changelog, if a value is not found, the original will be provided | -| `message_hook` | `method: (dict, git.GitCommit) -> dict` | NO | Customize with extra information your message output, like adding links, this function is executed per parsed commit. | +| `changelog_message_builder_hook` | `method: (dict, git.GitCommit) -> dict` | NO | Customize with extra information your message output, like adding links, this function is executed per parsed commit. | | `changelog_hook` | `method: (full_changelog: str, partial_changelog: Optional[str]) -> str` | NO | Receives the whole and partial (if used incremental) changelog. Useful to send slack messages or notify a compliance department. Must return the full_changelog | ```python @@ -160,7 +160,7 @@ class StrangeCommitizen(BaseCommitizen): "perf": "Performance improvements" } - def message_hook(self, parsed_message: dict, commit: git.GitCommit) -> dict: + def changelog_message_builder_hook(self, parsed_message: dict, commit: git.GitCommit) -> dict: rev = commit.rev m = parsed_message["message"] parsed_message["message"] = f"{m} {rev}" diff --git a/tests/test_changelog.py b/tests/test_changelog.py index 0a11810ecb..29b644619f 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -715,15 +715,19 @@ def test_render_changelog_with_change_type(gitcommits, tags): assert new_title in result -def test_render_changelog_with_message_hook(gitcommits, tags): - def message_hook(message: dict, _) -> dict: +def test_render_changelog_with_changelog_message_builder_hook(gitcommits, tags): + def changelog_message_builder_hook(message: dict, _) -> dict: message["message"] = f"{message['message']} [link](github.com/232323232)" return message parser = defaults.commit_parser changelog_pattern = defaults.bump_pattern tree = changelog.generate_tree_from_commits( - gitcommits, tags, parser, changelog_pattern, message_hook=message_hook + gitcommits, + tags, + parser, + changelog_pattern, + changelog_message_builder_hook=changelog_message_builder_hook, ) result = changelog.render_changelog(tree) assert "[link](github.com/232323232)" in result From d28f6b77adc9e6cef863aeb1951c22a385f924fd Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 13 May 2020 11:36:52 +0000 Subject: [PATCH 122/427] =?UTF-8?q?bump:=20version=201.21.0=20=E2=86=92=20?= =?UTF-8?q?1.22.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 13 +++++++++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44a2287b8e..d63d6c2b0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ + +## v1.22.0 (2020-05-13) + +### Fix + +- **changelog**: rename `message_hook` -> `changelog_message_builder_hook` + +### Feat + +- **changelog**: add support for `changelog_hook` when changelog finishes the generation +- **changelog**: add support for `message_hook` method +- **changelog**: add support for modifying the change_type in the title of the changelog + ## v1.21.0 (2020-05-09) ### Feat diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 6df86cae31..eb9596372c 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.21.0" +__version__ = "1.22.0" diff --git a/pyproject.toml b/pyproject.toml index 327cb049ae..72dfc6e815 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.21.0" +version = "1.22.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.21.0" +version = "1.22.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From d96cae2a16956c8ce1ce8ee1733b2672dace9c90 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Wed, 20 May 2020 23:42:05 +0800 Subject: [PATCH 123/427] docs(github): add issue_template for feature_request, bug_report and documentation --- .github/ISSUE_TEMPLATE/bug_report.md | 30 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/documentation.md | 18 ++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 19 ++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/documentation.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000..2281f35e7d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,30 @@ +--- +name: 🛠 Bug report +about: Create a report to help us improve +title: "[Bug Report] Good bug title tells us about precise symptom, not about the root cause." +labels: "bug" +assignees: "" +--- + +## Description +A clear and concise description of what the bug is. + +## commitizen version +x.y.z + +## Steps to Reproduce +Steps to reproduce the behavior: +1. Run ... +2. ... +3. ... + +## Expected Behavior +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +## Actual Behavior +What happens actually so you think this is a bug. + +## More Information diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md new file mode 100644 index 0000000000..d1543dc40f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.md @@ -0,0 +1,18 @@ +--- +name: 📖 Documentation +about: Suggest an improvement for the documentation of this project +title: "[Documentation] Content to be added or fixed" +labels: "documentation" +assignees: "" +--- + +## Type +* [ ] Conent inaccurate +* [ ] Content missing +* [ ] Typo + +## URL +URL to the code we did not clearly describe or the document page where the content is inaccurate + +## Description +A clear and concise description of what content should be added or fixed diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000..b43e366394 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,19 @@ +--- +name: 🚀 Feature request +about: Suggest an idea for this project +title: "[Feature Request] <One feature request per issue>" +labels: "" +assignees: "" +--- + +## Description +A clear and concise description for us to know your idea. + +## Possible Solution +A clear and concise description of what you want to happen. + +## Additional context +Add any other context or screenshots about the feature request here. + +## Related Issue +If applicable, add link to existing issue also help us know better. From 4399ba15e546ba3538a49959453deb09cb0d1270 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Wed, 20 May 2020 23:42:23 +0800 Subject: [PATCH 124/427] docs(github): add more content to pull_requset template --- .github/pull_request_template.md | 35 +++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index ceff272b01..82d423a897 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,10 +1,35 @@ -## Related Issue +(Thanks for sending a pull request! Please fill in the following content to let us know better about this change.) -## Detail +## Types of changes +Please put an `x` in the box that applies -## Checklist: +- [ ] **Bugfix** +- [ ] **New feature** +- [ ] **Refactoring** +- [ ] **Breaking change** (any change that would cause existing functionality to not work as expected) +- [ ] **Documentation Update** +- [ ] **Other (please describe)** + +## Description +**Describe what the change is** -- [ ] Run "./script/lint" and "./script/test" locally to ensure this change passes linter check and test -- [ ] Add test cases to all the changes +## Checklist: +- [ ] Add test cases to all the changes you introduce +- [ ] Run `./script/lint` and `./script/test` locally to ensure this change passes linter check and test - [ ] Test the changes on the local machine manually - [ ] Update the documentation for the changes + +## Steps to Test This Pull Request +Steps to reproduce the behavior: +1. ... +2. ... +3. ... + +## Expected behavior +A clear and concise description of what you expected to happen + +## Related Issue +If applicable, reference to the issue related to this pull request. + +## Additional context +Add any other context or screenshots about the pull request here. From 4abf2bbbf43d48257d8d5bd126c4979fd2b45d19 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Fri, 22 May 2020 22:18:30 +0800 Subject: [PATCH 125/427] build(poetry): add pydocstyle as dev dependecies --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 72dfc6e815..d0bdcc051e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,6 +67,7 @@ mkdocs = "^1.0" mkdocs-material = "^4.1" isort = "^4.3.21" freezegun = "^0.3.15" +pydocstyle = "^5.0.2" [tool.poetry.scripts] cz = "commitizen.cli:main" From 546c4426aca745e84fca33524065623f47421804 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Fri, 22 May 2020 22:19:10 +0800 Subject: [PATCH 126/427] ci(scripts/test): add pydocstyle google convention to change docstring style --- scripts/test | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/test b/scripts/test index 86c1669a10..6b4f81c81b 100755 --- a/scripts/test +++ b/scripts/test @@ -10,3 +10,4 @@ ${PREFIX}black commitizen tests --check ${PREFIX}isort --recursive --check-only commitizen tests ${PREFIX}flake8 commitizen/ tests/ ${PREFIX}mypy commitizen/ tests/ +${PREFIX}pydocstyle --convention=google --add-ignore=D1,D415 From b4e2a584aa632b2bc4487d39bc0214fa0cdbae8b Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Fri, 22 May 2020 22:22:04 +0800 Subject: [PATCH 127/427] style(docstring): unify docstring style --- commitizen/bump.py | 5 ++--- commitizen/changelog.py | 14 ++++++-------- commitizen/changelog_parser.py | 6 ++---- commitizen/commands/check.py | 21 +++++++-------------- commitizen/cz/base.py | 2 +- commitizen/git.py | 6 ++---- 6 files changed, 20 insertions(+), 34 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index ff99c3d427..63f1f70eba 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -55,7 +55,8 @@ def find_increment( def prerelease_generator(current_version: str, prerelease: Optional[str] = None) -> str: - """ + """Generate prerelease + X.YaN # Alpha release X.YbN # Beta release X.YrcN # Release Candidate @@ -179,13 +180,11 @@ def create_tag(version: Union[Version, str], tag_format: Optional[str] = None): That's why this function exists. Example: - | tag | version (PEP 0440) | | --- | ------- | | v0.9.0 | 0.9.0 | | ver1.0.0 | 1.0.0 | | ver1.0.0.a0 | 1.0.0a0 | - """ if isinstance(version, str): version = Version(version) diff --git a/commitizen/changelog.py b/commitizen/changelog.py index bde2d51763..620c6ade29 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -1,5 +1,4 @@ -""" -# DESIGN +"""Design ## Metadata CHANGELOG.md @@ -62,7 +61,6 @@ def transform_change_type(change_type: str) -> str: def get_commit_tag(commit: GitCommit, tags: List[GitTag]) -> Optional[GitTag]: - """""" return next((tag for tag in tags if tag.rev == commit.rev), None) @@ -211,13 +209,13 @@ def incremental_build(new_content: str, lines: List, metadata: Dict) -> List: The metadata holds information enough to remove the old unreleased and where to place the new content - Arguments: - lines -- the lines from the changelog - new_content -- this should be placed somewhere in the lines - metadata -- information about the changelog + Args: + lines: The lines from the changelog + new_content: This should be placed somewhere in the lines + metadata: Information about the changelog Returns: - List -- updated lines + Updated lines """ unreleased_start = metadata.get("unreleased_start") unreleased_end = metadata.get("unreleased_end") diff --git a/commitizen/changelog_parser.py b/commitizen/changelog_parser.py index c945cbdb4f..e53c52893a 100644 --- a/commitizen/changelog_parser.py +++ b/commitizen/changelog_parser.py @@ -1,5 +1,4 @@ -""" -# DESIGN +"""CHNAGLOG PARSER DESIGN ## Parse CHANGELOG.md @@ -36,8 +35,7 @@ def find_version_blocks(filepath: str) -> Generator: - """ - version block: contains all the information about a version. + """Find version block (version block: contains all the information about a version.) E.g: ``` diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py index beadc4b392..4d1d4bb344 100644 --- a/commitizen/commands/check.py +++ b/commitizen/commands/check.py @@ -12,16 +12,12 @@ class Check: """Check if the current commit msg matches the commitizen format.""" def __init__(self, config: BaseConfig, arguments: Dict[str, str], cwd=os.getcwd()): - """Init method. - - Parameters - ---------- - config : BaseConfig - 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 + """Initial check command. + Args: + config: The config object required for the command to perform its action + arguments: All the flags provided by the user + cwd: Current work directory """ self.commit_msg_file: Optional[str] = arguments.get("commit_msg_file") self.rev_range: Optional[str] = arguments.get("rev_range") @@ -44,11 +40,8 @@ def _valid_command_argument(self): def __call__(self): """Validate if commit messages follows the conventional pattern. - Raises - ------ - SystemExit - if the commit provided not follows the conventional pattern - + Raises: + SystemExit: if the commit provided not follows the conventional pattern """ commit_msgs = self._get_commit_messages() if not commit_msgs: diff --git a/commitizen/cz/base.py b/commitizen/cz/base.py index ddf0c7997c..5871879992 100644 --- a/commitizen/cz/base.py +++ b/commitizen/cz/base.py @@ -69,7 +69,7 @@ def schema(self) -> Optional[str]: raise NotImplementedError("Not Implemented yet") def schema_pattern(self) -> Optional[str]: - """Regex matching the schema used for message validation""" + """Regex matching the schema used for message validation.""" raise NotImplementedError("Not Implemented yet") def info(self) -> Optional[str]: diff --git a/commitizen/git.py b/commitizen/git.py index 76abb17ade..e26167f3b0 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -63,9 +63,7 @@ def get_commits( delimiter: str = "----------commit-delimiter----------", args: str = "", ) -> List[GitCommit]: - """ - Get the commits betweeen start and end - """ + """Get the commits betweeen start and end.""" git_log_cmd = f"git log --pretty={log_format}{delimiter} {args}" if start: @@ -133,7 +131,7 @@ def find_git_project_root() -> Optional[Path]: def is_staging_clean() -> bool: - """Check if staing is clean""" + """Check if staing is clean.""" c = cmd.run("git diff --no-ext-diff --name-only") c_cached = cmd.run("git diff --no-ext-diff --cached --name-only") return not (bool(c.out) or bool(c_cached.out)) From 62408e8c9aaafe8384d609a35ea31931862dfd24 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Fri, 22 May 2020 22:23:38 +0800 Subject: [PATCH 128/427] fix(templates): remove trailing space in keep_a_changelog --- .../templates/keep_a_changelog_template.j2 | 2 +- tests/commands/test_changelog_command.py | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/commitizen/templates/keep_a_changelog_template.j2 b/commitizen/templates/keep_a_changelog_template.j2 index 381fe88bf3..de63880d66 100644 --- a/commitizen/templates/keep_a_changelog_template.j2 +++ b/commitizen/templates/keep_a_changelog_template.j2 @@ -1,6 +1,6 @@ {% for entry in tree %} -## {{ entry.version }} {% if entry.date %}({{ entry.date }}){% endif %} +## {{ entry.version }}{% if entry.date %} ({{ entry.date }}){% endif %} {% for change_key, changes in entry.changes.items() %} diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index a676295c4c..76fad0be04 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -38,7 +38,7 @@ def test_changlog_from_version_zero_point_two(mocker, capsys): cli.main() out, _ = capsys.readouterr() - assert out == "\n## Unreleased \n\n### Feat\n\n- after 0.2\n- after 0.2.0\n\n" + assert out == "\n## Unreleased\n\n### Feat\n\n- after 0.2\n- after 0.2.0\n\n" @pytest.mark.usefixtures("tmp_commitizen_project") @@ -54,7 +54,7 @@ def test_changlog_with_different_cz(mocker, capsys): out, _ = capsys.readouterr() assert ( out - == "\n## Unreleased \n\n\n- JRA-35 #time 1w 2d 4h 30m Total work logged\n- JRA-34 #comment corrected indent issue\n\n" + == "\n## Unreleased\n\n\n- JRA-35 #time 1w 2d 4h 30m Total work logged\n- JRA-34 #comment corrected indent issue\n\n" ) @@ -74,7 +74,7 @@ def test_changlog_from_start(mocker, capsys): assert ( out - == "\n## Unreleased \n\n### Refactor\n\n- is in changelog\n\n### Feat\n\n- new file\n" + == "\n## Unreleased\n\n### Refactor\n\n- is in changelog\n\n### Feat\n\n- new file\n" ) @@ -108,7 +108,7 @@ def test_changlog_replacing_unreleased_using_incremental(mocker, capsys): today = date.today().isoformat() assert ( out - == f"\n\n## Unreleased \n\n### Feat\n\n- add more stuff\n\n### Fix\n\n- mama gotta work\n\n## 0.2.0 ({today})\n\n### Fix\n\n- output glitch\n\n### Feat\n\n- add new output\n" + == f"\n\n## Unreleased\n\n### Feat\n\n- add more stuff\n\n### Fix\n\n- mama gotta work\n\n## 0.2.0 ({today})\n\n### Fix\n\n- output glitch\n\n### Feat\n\n- add new output\n" ) @@ -146,7 +146,7 @@ def test_changlog_is_persisted_using_incremental(mocker, capsys): today = date.today().isoformat() assert ( out - == f"\n\n## Unreleased \n\n### Feat\n\n- add more stuff\n\n### Fix\n\n- mama gotta work\n\n## 0.2.0 ({today})\n\n### Fix\n\n- output glitch\n\n### Feat\n\n- add new output\n\nnote: this should be persisted using increment\n" + == f"\n\n## Unreleased\n\n### Feat\n\n- add more stuff\n\n### Fix\n\n- mama gotta work\n\n## 0.2.0 ({today})\n\n### Fix\n\n- output glitch\n\n### Feat\n\n- add new output\n\nnote: this should be persisted using increment\n" ) @@ -180,7 +180,7 @@ def test_changlog_incremental_angular_sample(mocker, capsys): assert ( out - == "\n## Unreleased \n\n### Feat\n\n- add more stuff\n- add new output\n\n### Fix\n\n- mama gotta work\n- output glitch\n\n# [10.0.0-next.3](https://github.com/angular/angular/compare/10.0.0-next.2...10.0.0-next.3) (2020-04-22)\n\n### Bug Fixes\n* **common:** format day-periods that cross midnight ([#36611](https://github.com/angular/angular/issues/36611)) ([c6e5fc4](https://github.com/angular/angular/commit/c6e5fc4)), closes [#36566](https://github.com/angular/angular/issues/36566)\n" + == "\n## Unreleased\n\n### Feat\n\n- add more stuff\n- add new output\n\n### Fix\n\n- mama gotta work\n- output glitch\n\n# [10.0.0-next.3](https://github.com/angular/angular/compare/10.0.0-next.2...10.0.0-next.3) (2020-04-22)\n\n### Bug Fixes\n* **common:** format day-periods that cross midnight ([#36611](https://github.com/angular/angular/issues/36611)) ([c6e5fc4](https://github.com/angular/angular/commit/c6e5fc4)), closes [#36566](https://github.com/angular/angular/issues/36566)\n" ) @@ -233,7 +233,7 @@ def test_changlog_incremental_keep_a_changelog_sample(mocker, capsys): assert ( out - == """# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n\n## Unreleased \n\n### Feat\n\n- add more stuff\n- add new output\n\n### Fix\n\n- mama gotta work\n- output glitch\n\n## [1.0.0] - 2017-06-20\n### Added\n- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).\n- Version navigation.\n\n### Changed\n- Start using "changelog" over "change log" since it\'s the common usage.\n\n### Removed\n- Section about "changelog" vs "CHANGELOG".\n\n## [0.3.0] - 2015-12-03\n### Added\n- RU translation from [@aishek](https://github.com/aishek).\n""" + == """# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n\n## Unreleased\n\n### Feat\n\n- add more stuff\n- add new output\n\n### Fix\n\n- mama gotta work\n- output glitch\n\n## [1.0.0] - 2017-06-20\n### Added\n- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).\n- Version navigation.\n\n### Changed\n- Start using "changelog" over "change log" since it\'s the common usage.\n\n### Removed\n- Section about "changelog" vs "CHANGELOG".\n\n## [0.3.0] - 2015-12-03\n### Added\n- RU translation from [@aishek](https://github.com/aishek).\n""" ) @@ -251,6 +251,6 @@ def test_changlog_hook(mocker, config): ) mocker.patch.object(changelog.cz, "changelog_hook", changelog_hook_mock) changelog() - full_changelog = "\n## Unreleased \n\n### Refactor\n\n- is in changelog\n\n### Feat\n\n- new file\n" + full_changelog = "\n## Unreleased\n\n### Refactor\n\n- is in changelog\n\n### Feat\n\n- new file\n" changelog_hook_mock.assert_called_with(full_changelog, full_changelog) From 43ff9c290be4f6e63c43ee55b01039aee1a178b1 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Fri, 22 May 2020 22:36:47 +0800 Subject: [PATCH 129/427] docs(tutorials/github_actions): add pypa/gh-action-pypi-publish as reference #161 --- docs/tutorials/github_actions.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/tutorials/github_actions.md b/docs/tutorials/github_actions.md index 683a8a9de9..c0784dac9f 100644 --- a/docs/tutorials/github_actions.md +++ b/docs/tutorials/github_actions.md @@ -97,5 +97,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/commitizen-tools/commitizen/blob/master/scripts/publish) +You can also use [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) to publish your package. Push the changes and that's it. From 71e509cf4315bdbdf55e936d2249e9393fc1200d Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Fri, 22 May 2020 23:59:19 +0800 Subject: [PATCH 130/427] ci(scripts/test): add commit check --- scripts/test | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/test b/scripts/test index 6b4f81c81b..db6f55efa6 100755 --- a/scripts/test +++ b/scripts/test @@ -11,3 +11,4 @@ ${PREFIX}isort --recursive --check-only commitizen tests ${PREFIX}flake8 commitizen/ tests/ ${PREFIX}mypy commitizen/ tests/ ${PREFIX}pydocstyle --convention=google --add-ignore=D1,D415 +${PREFIX}commitizen check --rev-range master.. From 2c9c8a380edf0116515b77fdf16cf7ef78b6fca0 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 23 May 2020 15:54:16 +0800 Subject: [PATCH 131/427] style: fix typo within codebase --- commitizen/bump.py | 2 +- commitizen/cli.py | 2 +- commitizen/commands/bump.py | 2 +- commitizen/config/__init__.py | 2 +- commitizen/factory.py | 2 +- commitizen/git.py | 2 +- tests/CHANGELOG_FOR_TEST.md | 8 ++++---- tests/commands/test_bump_command.py | 2 +- tests/test_changelog.py | 16 ++++++++-------- tests/test_cz_customize.py | 10 +++++----- 10 files changed, 24 insertions(+), 24 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index 63f1f70eba..97b7c452ff 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -138,7 +138,7 @@ def update_version_in_files( So for example, your tag could look like `v1.0.0` while your version in the package like `1.0.0`. """ - # TODO: sepearte check step and write step + # TODO: separate check step and write step for location in files: filepath, *regexes = location.split(":", maxsplit=1) regex = regexes[0] if regexes else None diff --git a/commitizen/cli.py b/commitizen/cli.py index 3bb6f2843f..3ceee55f70 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -114,7 +114,7 @@ { "name": "--bump-message", "help": ( - "template used to create the release commmit, " + "template used to create the release commit, " "useful when working with CI" ), }, diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 61d40d16eb..2746127e50 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -154,7 +154,7 @@ def __call__(self): # noqa: C901 self.config.set_key("version", new_version.public) c = git.commit(message, args=self._get_commit_args()) if c.err: - out.error('git.commit errror: "{}"'.format(c.err.strip())) + out.error('git.commit error: "{}"'.format(c.err.strip())) raise SystemExit(COMMIT_FAILED) c = git.tag(new_tag_version) if c.err: diff --git a/commitizen/config/__init__.py b/commitizen/config/__init__.py index b0dbd7bdc4..2f2ee914a5 100644 --- a/commitizen/config/__init__.py +++ b/commitizen/config/__init__.py @@ -16,7 +16,7 @@ def load_global_conf() -> Optional[IniConfig]: if not global_cfg.exists(): return None - # global conf doesnt make sense with commitizen bump + # global conf doesn't make sense with commitizen bump # so I'm deprecating it and won't test it message = ( "Global conf will be deprecated in next major version. " diff --git a/commitizen/factory.py b/commitizen/factory.py index 8dab0c408a..a589d8c205 100644 --- a/commitizen/factory.py +++ b/commitizen/factory.py @@ -11,7 +11,7 @@ def commiter_factory(config: BaseConfig) -> BaseCommitizen: _cz = registry[name](config) except KeyError: msg_error = ( - "The commiter has not been found in the system.\n\n" + "The committer has not been found in the system.\n\n" f"Try running 'pip install {name}'\n" ) out.error(msg_error) diff --git a/commitizen/git.py b/commitizen/git.py index e26167f3b0..3db37111be 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -63,7 +63,7 @@ def get_commits( delimiter: str = "----------commit-delimiter----------", args: str = "", ) -> List[GitCommit]: - """Get the commits betweeen start and end.""" + """Get the commits between start and end.""" git_log_cmd = f"git log --pretty={log_format}{delimiter} {args}" if start: diff --git a/tests/CHANGELOG_FOR_TEST.md b/tests/CHANGELOG_FOR_TEST.md index 798b07545a..e92ca1ce39 100644 --- a/tests/CHANGELOG_FOR_TEST.md +++ b/tests/CHANGELOG_FOR_TEST.md @@ -29,7 +29,7 @@ - update given files with new version - **config**: new set key, used to set version to cfg - support for pyproject.toml -- first semantic version bump implementaiton +- first semantic version bump implementation ### fix @@ -92,11 +92,11 @@ ### refactor -- **conventionalCommit**: moved fitlers to questions instead of message +- **conventionalCommit**: moved filters to questions instead of message ### fix -- **manifest**: inluded missing files +- **manifest**: included missing files ## v0.9.5 (2018-08-24) @@ -114,7 +114,7 @@ ### feat -- **commiter**: conventional commit is a bit more intelligent now +- **committer**: conventional commit is a bit more intelligent now ## v0.9.2 (2017-11-11) diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index 84f26db42d..a7c431720e 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -77,7 +77,7 @@ def test_bump_on_git_with_hooks_no_verify_disabled(mocker, capsys): cli.main() _, err = capsys.readouterr() - assert 'git.commit errror: "0.1.0"' in err + assert 'git.commit error: "0.1.0"' in err @pytest.mark.usefixtures("tmp_commitizen_project") diff --git a/tests/test_changelog.py b/tests/test_changelog.py index 29b644619f..9675802e43 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -125,7 +125,7 @@ }, { "rev": "3127e05077288a5e2b62893345590bf1096141b7", - "title": "feat: first semantic version bump implementaiton", + "title": "feat: first semantic version bump implementation", "body": "", }, { @@ -255,12 +255,12 @@ }, { "rev": "72472efb80f08ee3fd844660afa012c8cb256e4b", - "title": "refactor(conventionalCommit): moved fitlers to questions instead of message", + "title": "refactor(conventionalCommit): moved filters to questions instead of message", "body": "", }, { "rev": "b5561ce0ab3b56bb87712c8f90bcf37cf2474f1b", - "title": "fix(manifest): inluded missing files", + "title": "fix(manifest): included missing files", "body": "", }, { @@ -290,7 +290,7 @@ }, { "rev": "4368f3c3cbfd4a1ced339212230d854bc5bab496", - "title": "feat(commiter): conventional commit is a bit more intelligent now", + "title": "feat(committer): conventional commit is a bit more intelligent now", "body": "", }, { @@ -472,7 +472,7 @@ def test_generate_tree_from_commits(gitcommits, tags): { "scope": None, "breaking": None, - "message": "first semantic version bump implementaiton", + "message": "first semantic version bump implementation", }, ], "fix": [ @@ -591,14 +591,14 @@ def test_generate_tree_from_commits(gitcommits, tags): { "scope": "conventionalCommit", "breaking": None, - "message": "moved fitlers to questions instead of message", + "message": "moved filters to questions instead of message", } ], "fix": [ { "scope": "manifest", "breaking": None, - "message": "inluded missing files", + "message": "included missing files", } ], }, @@ -629,7 +629,7 @@ def test_generate_tree_from_commits(gitcommits, tags): "changes": { "feat": [ { - "scope": "commiter", + "scope": "committer", "breaking": None, "message": "conventional commit is a bit more intelligent now", } diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py index 3cc76eb9e0..23289d7d42 100644 --- a/tests/test_cz_customize.py +++ b/tests/test_cz_customize.py @@ -10,7 +10,7 @@ def config(): toml_str = r""" [tool.commitizen.customize] message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" - example = "feature: this feature eanable customize through config file" + example = "feature: this feature enable customize through config file" schema = "<type>: <body>" bump_pattern = "^(break|new|fix|hotfix)" bump_map = {"break" = "MAJOR", "new" = "MINOR", "fix" = "PATCH", "hotfix" = "PATCH"} @@ -88,16 +88,16 @@ def test_answer(config): cz = CustomizeCommitsCz(config) answers = { "change_type": "feature", - "message": "this feature eanable customize through config file", + "message": "this feature enaable customize through config file", "show_message": True, } message = cz.message(answers) - assert message == "feature: this feature eanable customize through config file" + assert message == "feature: this feature enaable customize through config file" cz = CustomizeCommitsCz(config) answers = { "change_type": "feature", - "message": "this feature eanable customize through config file", + "message": "this feature enaable customize through config file", "show_message": False, } message = cz.message(answers) @@ -106,7 +106,7 @@ def test_answer(config): def test_example(config): cz = CustomizeCommitsCz(config) - assert "feature: this feature eanable customize through config file" in cz.example() + assert "feature: this feature enable customize through config file" in cz.example() def test_schema(config): From 274179f539e39b7119fcbf09e4e4be8bf34b7a44 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 23 May 2020 16:16:28 +0800 Subject: [PATCH 132/427] ci(github-action): fix commit check error * load the full commit log when checkout * do not raise error if no commit to check (e.g. master branch) --- .github/workflows/pythonpackage.yml | 12 +++++++++++- scripts/test | 1 - 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 4efc8d90e0..957754c32e 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -12,7 +12,9 @@ jobs: python-version: [3.6, 3.7, 3.8] steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 + with: + fetch-depth: 0 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v1 with: @@ -27,6 +29,14 @@ jobs: git config --global user.email "action@github.com" git config --global user.name "GitHub Action" ./scripts/test + - name: Check commit + run: | + poetry run python -m commitizen check --rev-range ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} || \ + if [ $$? == 3 ] ; then + exit 0; + else + exit 1; + fi - name: Upload coverage to Codecov if: runner.os == 'Linux' uses: codecov/codecov-action@v1.0.3 diff --git a/scripts/test b/scripts/test index db6f55efa6..6b4f81c81b 100755 --- a/scripts/test +++ b/scripts/test @@ -11,4 +11,3 @@ ${PREFIX}isort --recursive --check-only commitizen tests ${PREFIX}flake8 commitizen/ tests/ ${PREFIX}mypy commitizen/ tests/ ${PREFIX}pydocstyle --convention=google --add-ignore=D1,D415 -${PREFIX}commitizen check --rev-range master.. From 601bd29edcc19f2ba8c6a30605b4d7e910f99e32 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sat, 23 May 2020 09:44:44 +0000 Subject: [PATCH 133/427] =?UTF-8?q?bump:=20version=201.22.0=20=E2=86=92=20?= =?UTF-8?q?1.22.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 7 +++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d63d6c2b0e..766cd2b0e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ + +## v1.22.1 (2020-05-23) + +### Fix + +- **templates**: remove trailing space in keep_a_changelog + ## v1.22.0 (2020-05-13) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index eb9596372c..d91b718096 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.22.0" +__version__ = "1.22.1" diff --git a/pyproject.toml b/pyproject.toml index d0bdcc051e..742c25f154 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.22.0" +version = "1.22.1" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.22.0" +version = "1.22.1" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 11b177f06b5a46e4c6faa541897536e442b7854b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Fri, 29 May 2020 10:16:35 +0200 Subject: [PATCH 134/427] fix(changelog): empty lines at the beginning of the CHANGELOG Closes #192 --- CHANGELOG.md | 6 -- commitizen/commands/changelog.py | 1 + tests/commands/test_changelog_command.py | 76 ++++++++++++++++++------ 3 files changed, 58 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 766cd2b0e1..56be36ae49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,3 @@ - - - - - - ## v1.22.1 (2020-05-23) ### Fix diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 93cd26d793..8cc6baf0dc 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -100,6 +100,7 @@ def __call__(self): changelog_message_builder_hook=changelog_message_builder_hook, ) changelog_out = changelog.render_changelog(tree) + changelog_out = changelog_out.lstrip("\n") if self.dry_run: out.write(changelog_out) diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index 76fad0be04..bfe2ab780f 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -9,6 +9,11 @@ from tests.utils import create_file_and_commit +@pytest.fixture() +def changelog_path() -> str: + return os.path.join(os.getcwd(), "CHANGELOG.md") + + @pytest.mark.usefixtures("tmp_commitizen_project") def test_changlog_on_empty_project(mocker): testargs = ["cz", "changelog", "--dry-run"] @@ -38,7 +43,7 @@ def test_changlog_from_version_zero_point_two(mocker, capsys): cli.main() out, _ = capsys.readouterr() - assert out == "\n## Unreleased\n\n### Feat\n\n- after 0.2\n- after 0.2.0\n\n" + assert out == "## Unreleased\n\n### Feat\n\n- after 0.2\n- after 0.2.0\n\n" @pytest.mark.usefixtures("tmp_commitizen_project") @@ -54,13 +59,12 @@ def test_changlog_with_different_cz(mocker, capsys): out, _ = capsys.readouterr() assert ( out - == "\n## Unreleased\n\n\n- JRA-35 #time 1w 2d 4h 30m Total work logged\n- JRA-34 #comment corrected indent issue\n\n" + == "## Unreleased\n\n\n- JRA-35 #time 1w 2d 4h 30m Total work logged\n- JRA-34 #comment corrected indent issue\n\n" ) @pytest.mark.usefixtures("tmp_commitizen_project") -def test_changlog_from_start(mocker, capsys): - changelog_path = os.path.join(os.getcwd(), "CHANGELOG.md") +def test_changlog_from_start(mocker, capsys, changelog_path): create_file_and_commit("feat: new file") create_file_and_commit("refactor: is in changelog") create_file_and_commit("Merge into master") @@ -74,14 +78,14 @@ def test_changlog_from_start(mocker, capsys): assert ( out - == "\n## Unreleased\n\n### Refactor\n\n- is in changelog\n\n### Feat\n\n- new file\n" + == "## Unreleased\n\n### Refactor\n\n- is in changelog\n\n### Feat\n\n- new file\n" ) @pytest.mark.usefixtures("tmp_commitizen_project") -def test_changlog_replacing_unreleased_using_incremental(mocker, capsys): - changelog_path = os.path.join(os.getcwd(), "CHANGELOG.md") - +def test_changlog_replacing_unreleased_using_incremental( + mocker, capsys, changelog_path +): create_file_and_commit("feat: add new output") create_file_and_commit("fix: output glitch") create_file_and_commit("Merge into master") @@ -108,13 +112,12 @@ def test_changlog_replacing_unreleased_using_incremental(mocker, capsys): today = date.today().isoformat() assert ( out - == f"\n\n## Unreleased\n\n### Feat\n\n- add more stuff\n\n### Fix\n\n- mama gotta work\n\n## 0.2.0 ({today})\n\n### Fix\n\n- output glitch\n\n### Feat\n\n- add new output\n" + == f"## Unreleased\n\n### Feat\n\n- add more stuff\n\n### Fix\n\n- mama gotta work\n\n## 0.2.0 ({today})\n\n### Fix\n\n- output glitch\n\n### Feat\n\n- add new output\n" ) @pytest.mark.usefixtures("tmp_commitizen_project") -def test_changlog_is_persisted_using_incremental(mocker, capsys): - changelog_path = os.path.join(os.getcwd(), "CHANGELOG.md") +def test_changlog_is_persisted_using_incremental(mocker, capsys, changelog_path): create_file_and_commit("feat: add new output") create_file_and_commit("fix: output glitch") @@ -146,13 +149,12 @@ def test_changlog_is_persisted_using_incremental(mocker, capsys): today = date.today().isoformat() assert ( out - == f"\n\n## Unreleased\n\n### Feat\n\n- add more stuff\n\n### Fix\n\n- mama gotta work\n\n## 0.2.0 ({today})\n\n### Fix\n\n- output glitch\n\n### Feat\n\n- add new output\n\nnote: this should be persisted using increment\n" + == f"## Unreleased\n\n### Feat\n\n- add more stuff\n\n### Fix\n\n- mama gotta work\n\n## 0.2.0 ({today})\n\n### Fix\n\n- output glitch\n\n### Feat\n\n- add new output\n\nnote: this should be persisted using increment\n" ) @pytest.mark.usefixtures("tmp_commitizen_project") -def test_changlog_incremental_angular_sample(mocker, capsys): - changelog_path = os.path.join(os.getcwd(), "CHANGELOG.md") +def test_changlog_incremental_angular_sample(mocker, capsys, changelog_path): with open(changelog_path, "w") as f: f.write( "# [10.0.0-next.3](https://github.com/angular/angular/compare/10.0.0-next.2...10.0.0-next.3) (2020-04-22)\n" @@ -180,7 +182,7 @@ def test_changlog_incremental_angular_sample(mocker, capsys): assert ( out - == "\n## Unreleased\n\n### Feat\n\n- add more stuff\n- add new output\n\n### Fix\n\n- mama gotta work\n- output glitch\n\n# [10.0.0-next.3](https://github.com/angular/angular/compare/10.0.0-next.2...10.0.0-next.3) (2020-04-22)\n\n### Bug Fixes\n* **common:** format day-periods that cross midnight ([#36611](https://github.com/angular/angular/issues/36611)) ([c6e5fc4](https://github.com/angular/angular/commit/c6e5fc4)), closes [#36566](https://github.com/angular/angular/issues/36566)\n" + == "## Unreleased\n\n### Feat\n\n- add more stuff\n- add new output\n\n### Fix\n\n- mama gotta work\n- output glitch\n\n# [10.0.0-next.3](https://github.com/angular/angular/compare/10.0.0-next.2...10.0.0-next.3) (2020-04-22)\n\n### Bug Fixes\n* **common:** format day-periods that cross midnight ([#36611](https://github.com/angular/angular/issues/36611)) ([c6e5fc4](https://github.com/angular/angular/commit/c6e5fc4)), closes [#36566](https://github.com/angular/angular/issues/36566)\n" ) @@ -210,8 +212,7 @@ def test_changlog_incremental_angular_sample(mocker, capsys): @pytest.mark.usefixtures("tmp_commitizen_project") -def test_changlog_incremental_keep_a_changelog_sample(mocker, capsys): - changelog_path = os.path.join(os.getcwd(), "CHANGELOG.md") +def test_changlog_incremental_keep_a_changelog_sample(mocker, capsys, changelog_path): with open(changelog_path, "w") as f: f.write(KEEP_A_CHANGELOG) create_file_and_commit("irrelevant commit") @@ -233,7 +234,7 @@ def test_changlog_incremental_keep_a_changelog_sample(mocker, capsys): assert ( out - == """# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n\n## Unreleased\n\n### Feat\n\n- add more stuff\n- add new output\n\n### Fix\n\n- mama gotta work\n- output glitch\n\n## [1.0.0] - 2017-06-20\n### Added\n- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).\n- Version navigation.\n\n### Changed\n- Start using "changelog" over "change log" since it\'s the common usage.\n\n### Removed\n- Section about "changelog" vs "CHANGELOG".\n\n## [0.3.0] - 2015-12-03\n### Added\n- RU translation from [@aishek](https://github.com/aishek).\n""" + == """# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## Unreleased\n\n### Feat\n\n- add more stuff\n- add new output\n\n### Fix\n\n- mama gotta work\n- output glitch\n\n## [1.0.0] - 2017-06-20\n### Added\n- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8).\n- Version navigation.\n\n### Changed\n- Start using "changelog" over "change log" since it\'s the common usage.\n\n### Removed\n- Section about "changelog" vs "CHANGELOG".\n\n## [0.3.0] - 2015-12-03\n### Added\n- RU translation from [@aishek](https://github.com/aishek).\n""" ) @@ -251,6 +252,43 @@ def test_changlog_hook(mocker, config): ) mocker.patch.object(changelog.cz, "changelog_hook", changelog_hook_mock) changelog() - full_changelog = "\n## Unreleased\n\n### Refactor\n\n- is in changelog\n\n### Feat\n\n- new file\n" + full_changelog = ( + "## Unreleased\n\n### Refactor\n\n- is in changelog\n\n### Feat\n\n- new file\n" + ) changelog_hook_mock.assert_called_with(full_changelog, full_changelog) + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_changlog_multiple_incremental_do_not_add_new_lines( + mocker, capsys, changelog_path +): + """Test for bug https://github.com/commitizen-tools/commitizen/issues/192""" + create_file_and_commit("feat: add new output") + + testargs = ["cz", "changelog", "--incremental"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + + create_file_and_commit("fix: output glitch") + + testargs = ["cz", "changelog", "--incremental"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + + create_file_and_commit("fix: mama gotta work") + + testargs = ["cz", "changelog", "--incremental"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + + create_file_and_commit("feat: add more stuff") + + testargs = ["cz", "changelog", "--incremental"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + + with open(changelog_path, "r") as f: + out = f.read() + + assert out.startswith("#") From bbcc922a2558221f300912ada2c7822a217840ec Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Fri, 29 May 2020 11:13:40 +0000 Subject: [PATCH 135/427] =?UTF-8?q?bump:=20version=201.22.1=20=E2=86=92=20?= =?UTF-8?q?1.22.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56be36ae49..111c473238 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v1.22.2 (2020-05-29) + +### Fix + +- **changelog**: empty lines at the beginning of the CHANGELOG + ## v1.22.1 (2020-05-23) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index d91b718096..cbb09c4039 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.22.1" +__version__ = "1.22.2" diff --git a/pyproject.toml b/pyproject.toml index 742c25f154..933d685422 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.22.1" +version = "1.22.2" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.22.1" +version = "1.22.2" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From a60bd91710cdd2c13b146686abad9cf98bac818c Mon Sep 17 00:00:00 2001 From: Aadit Kamat <aadit.k12@gmail.com> Date: Mon, 1 Jun 2020 18:52:27 +0800 Subject: [PATCH 136/427] style(init): fix typo in init script I was trying out commitizen when I noticed the typo and so thought I would help fix it --- commitizen/commands/init.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commitizen/commands/init.py b/commitizen/commands/init.py index 31121cb0cf..c8ab4fb97e 100644 --- a/commitizen/commands/init.py +++ b/commitizen/commands/init.py @@ -32,7 +32,7 @@ def __call__(self): values_to_add["version"] = Version(tag).public values_to_add["tag_format"] = self._ask_tag_format(tag) self._update_config_file(values_to_add) - out.write("You can bump the version and create cangelog running:\n") + out.write("You can bump the version and create changelog running:\n") out.info("cz bump --changelog") out.success("The configuration are all set.") else: From 119d7294581b483f02d4e9a2324ec804e069ea4e Mon Sep 17 00:00:00 2001 From: bjoluc <mail@bjoluc.de> Date: Mon, 1 Jun 2020 15:49:49 +0200 Subject: [PATCH 137/427] build(dependencies): remove typing dependency The typing module is included in stdlib since Python 3.5. --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 933d685422..27f2e4a00c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,7 +52,6 @@ termcolor = "^1.1" packaging = ">=19,<21" tomlkit = "^0.5.3" jinja2 = "^2.10.3" -typing = "^3.7.4" [tool.poetry.dev-dependencies] ipython = "^7.2" From 17dd7ad85c8cd0389d9e00007a7bf6d4d72b4817 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Wed, 3 Jun 2020 22:56:25 +0800 Subject: [PATCH 138/427] docs: fix typo --- docs/bump.md | 2 +- docs/changelog.md | 4 ++-- docs/customization.md | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/bump.md b/docs/bump.md index efcef4a3b3..d09e3e1931 100644 --- a/docs/bump.md +++ b/docs/bump.md @@ -71,7 +71,7 @@ optional arguments: the format used to tag the commit and read it, use it in existing projects, wrap around simple quotes --bump-message BUMP_MESSAGE - template used to create the release commmit, useful + template used to create the release commit, useful when working with CI --prerelease {alpha,beta,rc}, -pr {alpha,beta,rc} choose type of prerelease diff --git a/docs/changelog.md b/docs/changelog.md index 2c78761324..a50b906df1 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,6 +1,6 @@ ## About -This command will generate a changelog following the commiting rules established. +This command will generate a changelog following the committing rules established. ## Usage @@ -66,7 +66,7 @@ and the following variables are expected: | `change_type` | The group where the commit belongs to, this is optional. Example: fix | `commit regex` | | `message`\* | Information extracted from the commit message | `commit regex` | | `scope` | Contextual information. Should be parsed using the regex from the message, it will be **bold** | `commit regex` | -| `breaking` | Wether is a breaking change or not | `commit regex` | +| `breaking` | Whether is a breaking change or not | `commit regex` | - **required**: is the only one required to be parsed by the regex diff --git a/docs/customization.md b/docs/customization.md index 721ade60b3..b74d086957 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -177,7 +177,7 @@ class StrangeCommitizen(BaseCommitizen): the new updated full_changelog """ if partial_changelog: - chat.room("#commiters").notify(partial_changelog) + chat.room("#committers").notify(partial_changelog) if full_changelog: compliance.send(full_changelog) full_changelog.replace(' fix ', ' **fix** ') @@ -214,7 +214,7 @@ name = "cz_customize" [tool.commitizen.customize] message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" -example = "feature: this feature eanable customize through config file" +example = "feature: this feature enable customize through config file" schema = "<type>: <body>" bump_pattern = "^(break|new|fix|hotfix)" bump_map = {"break" = "MAJOR", "new" = "MINOR", "fix" = "PATCH", "hotfix" = "PATCH"} From d85b649deacec2bb3f47709289b0a3067dedcc29 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Wed, 3 Jun 2020 23:40:20 +0800 Subject: [PATCH 139/427] docs: add github page link to README --- docs/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/README.md b/docs/README.md index 8aee8e4ea0..a7d4333b1d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,6 +9,8 @@ versions](https://img.shields.io/pypi/pyversions/commitizen.svg?style=flat-squar ![Using commitizen cli](images/demo.gif) +View full [documentation](https://commitizen-tools.github.io/commitizen/). + ## About Commitizen is a tool designed for teams. From 3983b1bb399d672582149d950a5fa2aa270341e2 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 6 Jun 2020 00:01:54 +0800 Subject: [PATCH 140/427] refactor(error_codes): remove unused NO_COMMIT_MSG error code --- commitizen/error_codes.py | 1 - 1 file changed, 1 deletion(-) diff --git a/commitizen/error_codes.py b/commitizen/error_codes.py index fa928e769d..93bf6cc4cb 100644 --- a/commitizen/error_codes.py +++ b/commitizen/error_codes.py @@ -21,7 +21,6 @@ CUSTOM_ERROR = 12 # Check -NO_COMMIT_MSG = 13 INVALID_COMMIT_MSG = 14 # Changelog From 8a518437c01eba40e347cc39d9716ec85d1ca3ef Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Fri, 5 Jun 2020 19:41:36 +0800 Subject: [PATCH 141/427] refactor: use custom exception for error handling The error code used is embedded into these exceptions --- commitizen/bump.py | 4 +- commitizen/cli.py | 12 +++ commitizen/commands/bump.py | 22 ++--- commitizen/commands/changelog.py | 14 ++- commitizen/commands/check.py | 6 +- commitizen/commands/commit.py | 24 ++--- commitizen/config/__init__.py | 9 +- commitizen/cz/customize/customize.py | 7 +- commitizen/error_codes.py | 27 ------ commitizen/exceptions.py | 104 +++++++++++++++++++++ commitizen/factory.py | 4 +- tests/commands/test_bump_command.py | 19 ++-- tests/commands/test_changelog_command.py | 3 +- tests/commands/test_check_command.py | 9 +- tests/commands/test_commit_command.py | 20 ++-- tests/test_bump_update_version_in_files.py | 5 +- tests/test_conf.py | 3 +- tests/test_cz_customize.py | 6 +- tests/test_factory.py | 3 +- 19 files changed, 199 insertions(+), 102 deletions(-) delete mode 100644 commitizen/error_codes.py create mode 100644 commitizen/exceptions.py diff --git a/commitizen/bump.py b/commitizen/bump.py index 97b7c452ff..f18cf97567 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -15,7 +15,7 @@ bump_message, bump_pattern, ) -from commitizen.error_codes import CURRENT_VERSION_NOT_FOUND +from commitizen.exceptions import CurrentVersionNotFoundError from commitizen.git import GitCommit @@ -167,7 +167,7 @@ def update_version_in_files( "The version defined in commitizen configuration and the ones in " "version_files are possibly inconsistent." ) - raise SystemExit(CURRENT_VERSION_NOT_FOUND) + raise CurrentVersionNotFoundError() # Write the file out again with open(filepath, "w") as file: diff --git a/commitizen/cli.py b/commitizen/cli.py index 3ceee55f70..eb0ce869eb 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -6,6 +6,7 @@ from decli import cli from commitizen import commands, config, out +from commitizen.exceptions import CommitizenException logger = logging.getLogger(__name__) data = { @@ -237,6 +238,17 @@ }, } +original_excepthook = sys.excepthook + + +def commitizen_excepthook(type, value, tracekback): + original_excepthook(type, value, tracekback) + if isinstance(value, CommitizenException): + sys.exit(value.exit_code) + + +sys.excepthook = commitizen_excepthook + def main(): conf = config.read_cfg() diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 2746127e50..57487bc5b2 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -6,12 +6,12 @@ from commitizen import bump, factory, git, out from commitizen.commands.changelog import Changelog from commitizen.config import BaseConfig -from commitizen.error_codes import ( - COMMIT_FAILED, - NO_COMMITS_FOUND, - NO_PATTERN_MAP, - NO_VERSION_SPECIFIED, - TAG_FAILED, +from commitizen.exceptions import ( + CommitFailedError, + NoCommitsFoundError, + NoPatternMapError, + NoVersionSpecifiedError, + TagFailedError, ) @@ -57,7 +57,7 @@ def find_increment(self, commits: List[git.GitCommit]) -> Optional[str]: bump_map = self.cz.bump_map if not bump_map or not bump_pattern: out.error(f"'{self.config.settings['name']}' rule does not support bump") - raise SystemExit(NO_PATTERN_MAP) + raise NoPatternMapError() increment = bump.find_increment( commits, regex=bump_pattern, increments_map=bump_map ) @@ -73,7 +73,7 @@ def __call__(self): # noqa: C901 "Check if current version is specified in config file, like:\n" "version = 0.4.3\n" ) - raise SystemExit(NO_VERSION_SPECIFIED) + raise NoVersionSpecifiedError() # Initialize values from sources (conf) current_version: str = self.config.settings["version"] @@ -102,7 +102,7 @@ def __call__(self): # noqa: C901 # Unless we previously had a prerelease. if not commits and not current_version_instance.is_prerelease: out.error("[NO_COMMITS_FOUND]\n" "No new commits found.") - raise SystemExit(NO_COMMITS_FOUND) + raise NoCommitsFoundError() if increment is None: increment = self.find_increment(commits) @@ -155,11 +155,11 @@ def __call__(self): # noqa: C901 c = git.commit(message, args=self._get_commit_args()) if c.err: out.error('git.commit error: "{}"'.format(c.err.strip())) - raise SystemExit(COMMIT_FAILED) + raise CommitFailedError() c = git.tag(new_tag_version) if c.err: out.error(c.err) - raise SystemExit(TAG_FAILED) + raise TagFailedError() out.success("Done!") def _get_commit_args(self): diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 8cc6baf0dc..92fa876764 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -5,7 +5,11 @@ from commitizen import changelog, factory, git, out from commitizen.config import BaseConfig -from commitizen.error_codes import NO_COMMITS_FOUND, NO_PATTERN_MAP, NO_REVISION +from commitizen.exceptions import ( + NoCommitsFoundError, + NoPatternMapError, + NoRevisionError, +) from commitizen.git import GitTag @@ -51,9 +55,9 @@ def _find_incremental_rev(self, latest_version: str, tags: List[GitTag]) -> str: try: score, tag = max(tag_ratio, key=itemgetter(0)) except ValueError: - raise SystemExit(NO_REVISION) + raise NoRevisionError() if score < SIMILARITY_THRESHOLD: - raise SystemExit(NO_REVISION) + raise NoRevisionError() start_rev = tag.name return start_rev @@ -73,7 +77,7 @@ def __call__(self): out.error( f"'{self.config.settings['name']}' rule does not support changelog" ) - raise SystemExit(NO_PATTERN_MAP) + raise NoPatternMapError() tags = git.get_tags() if not tags: @@ -88,7 +92,7 @@ def __call__(self): commits = git.get_commits(start=start_rev, args="--author-date-order") if not commits: out.error("No commits found") - raise SystemExit(NO_COMMITS_FOUND) + raise NoCommitsFoundError() tree = changelog.generate_tree_from_commits( commits, diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py index 4d1d4bb344..bb6724e2bf 100644 --- a/commitizen/commands/check.py +++ b/commitizen/commands/check.py @@ -5,7 +5,7 @@ from commitizen import factory, git, out from commitizen.config import BaseConfig -from commitizen.error_codes import INVALID_COMMIT_MSG, NO_COMMITS_FOUND +from commitizen.exceptions import InvalidCommitMessageError, NoCommitsFoundError class Check: @@ -46,7 +46,7 @@ def __call__(self): commit_msgs = self._get_commit_messages() if not commit_msgs: warnings.warn(f"No commit found with range: '{self.rev_range}'") - raise SystemExit(NO_COMMITS_FOUND) + raise NoCommitsFoundError() pattern = self.cz.schema_pattern() for commit_msg in commit_msgs: @@ -57,7 +57,7 @@ def __call__(self): f"commit: {commit_msg}\n" f"pattern: {pattern}" ) - raise SystemExit(INVALID_COMMIT_MSG) + raise InvalidCommitMessageError() out.success("Commit validation: successful!") def _get_commit_messages(self): diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index 57444011fd..7dc82f1242 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -7,12 +7,12 @@ from commitizen import factory, git, out from commitizen.config import BaseConfig from commitizen.cz.exceptions import CzException -from commitizen.error_codes import ( - COMMIT_ERROR, - CUSTOM_ERROR, - NO_ANSWERS, - NO_COMMIT_BACKUP, - NOTHING_TO_COMMIT, +from commitizen.exceptions import ( + CommitError, + CustomError, + NoAnswersError, + NoCommitBackupError, + NothingToCommitError, ) @@ -29,7 +29,7 @@ def read_backup_message(self) -> str: # Check the commit backup file exists if not os.path.isfile(self.temp_file): out.error("No commit backup found") - raise SystemExit(NO_COMMIT_BACKUP) + raise NoCommitBackupError() # Read commit message from backup with open(self.temp_file, "r") as f: @@ -45,11 +45,11 @@ def prompt_commit_questions(self) -> str: root_err = err.__context__ if isinstance(root_err, CzException): out.error(root_err.__str__()) - raise SystemExit(CUSTOM_ERROR) + raise CustomError() raise err if not answers: - raise SystemExit(NO_ANSWERS) + raise NoAnswersError() return cz.message(answers) def __call__(self): @@ -57,7 +57,7 @@ def __call__(self): if git.is_staging_clean() and not dry_run: out.write("No files added to staging!") - raise SystemExit(NOTHING_TO_COMMIT) + raise NothingToCommitError() retry: bool = self.arguments.get("retry") @@ -69,7 +69,7 @@ def __call__(self): out.info(f"\n{m}\n") if dry_run: - raise SystemExit(NOTHING_TO_COMMIT) + raise NothingToCommitError() c = git.commit(m) @@ -80,7 +80,7 @@ def __call__(self): with open(self.temp_file, "w") as f: f.write(m) - raise SystemExit(COMMIT_ERROR) + raise CommitError() if "nothing added" in c.out or "no changes added to commit" in c.out: out.error(c.out) diff --git a/commitizen/config/__init__.py b/commitizen/config/__init__.py index 2f2ee914a5..4219306011 100644 --- a/commitizen/config/__init__.py +++ b/commitizen/config/__init__.py @@ -2,8 +2,8 @@ from pathlib import Path from typing import Optional, Union -from commitizen import defaults, git, out -from commitizen.error_codes import NOT_A_GIT_PROJECT +from commitizen import defaults, git +from commitizen.exceptions import NotAGitProjectError from .base_config import BaseConfig from .ini_config import IniConfig @@ -38,10 +38,7 @@ def read_cfg() -> BaseConfig: git_project_root = git.find_git_project_root() if not git_project_root: - out.error( - "fatal: not a git repository (or any of the parent directories): .git" - ) - raise SystemExit(NOT_A_GIT_PROJECT) + raise NotAGitProjectError() cfg_paths = ( path / Path(filename) diff --git a/commitizen/cz/customize/customize.py b/commitizen/cz/customize/customize.py index 28d1b13738..02ce3711e6 100644 --- a/commitizen/cz/customize/customize.py +++ b/commitizen/cz/customize/customize.py @@ -5,10 +5,10 @@ from typing import Any, Dict, List, Optional -from commitizen import defaults, out +from commitizen import defaults from commitizen.config import BaseConfig from commitizen.cz.base import BaseCommitizen -from commitizen.error_codes import MISSING_CONFIG +from commitizen.exceptions import MissingConfigError __all__ = ["CustomizeCommitsCz"] @@ -21,8 +21,7 @@ def __init__(self, config: BaseConfig): super(CustomizeCommitsCz, self).__init__(config) if "customize" not in self.config.settings: - out.error("fatal: customize is not set in configuration file.") - raise SystemExit(MISSING_CONFIG) + raise MissingConfigError() self.custom_settings = self.config.settings["customize"] custom_bump_pattern = self.custom_settings.get("bump_pattern") diff --git a/commitizen/error_codes.py b/commitizen/error_codes.py deleted file mode 100644 index 93bf6cc4cb..0000000000 --- a/commitizen/error_codes.py +++ /dev/null @@ -1,27 +0,0 @@ -# Commitizen factory -NO_COMMITIZEN_FOUND = 1 - -# Config -NOT_A_GIT_PROJECT = 2 -MISSING_CONFIG = 15 - -# Bump -NO_COMMITS_FOUND = 3 -NO_VERSION_SPECIFIED = 4 -NO_PATTERN_MAP = 5 -COMMIT_FAILED = 6 -TAG_FAILED = 7 -CURRENT_VERSION_NOT_FOUND = 17 - -# Commit -NO_ANSWERS = 8 -COMMIT_ERROR = 9 -NO_COMMIT_BACKUP = 10 -NOTHING_TO_COMMIT = 11 -CUSTOM_ERROR = 12 - -# Check -INVALID_COMMIT_MSG = 14 - -# Changelog -NO_REVISION = 16 diff --git a/commitizen/exceptions.py b/commitizen/exceptions.py new file mode 100644 index 0000000000..c936583ebe --- /dev/null +++ b/commitizen/exceptions.py @@ -0,0 +1,104 @@ +import enum + +from commitizen import out + + +class ExitCode(enum.IntEnum): + NO_COMMITIZEN_FOUND = 1 + + NOT_A_GIT_PROJECT = 2 + MISSING_CONFIG = 15 + + NO_COMMITS_FOUND = 3 + NO_VERSION_SPECIFIED = 4 + NO_PATTERN_MAP = 5 + COMMIT_FAILED = 6 + TAG_FAILED = 7 + CURRENT_VERSION_NOT_FOUND = 17 + + NO_ANSWERS = 8 + COMMIT_ERROR = 9 + NO_COMMIT_BACKUP = 10 + NOTHING_TO_COMMIT = 11 + CUSTOM_ERROR = 12 + + INVALID_COMMIT_MSG = 14 + + # Changelog + NO_REVISION = 16 + + +class CommitizenException(Exception): + pass + + +class NoCommitizenFoundException(CommitizenException): + exit_code = ExitCode.NO_COMMITIZEN_FOUND + + +class NotAGitProjectError(CommitizenException): + exit_code = ExitCode.NOT_A_GIT_PROJECT + + def __init__(self, *args, **kwargs): + out.error( + "fatal: not a git repository (or any of the parent directories): .git" + ) + + +class MissingConfigError(CommitizenException): + exit_code = ExitCode.MISSING_CONFIG + + def __init__(self, *args, **kwargs): + out.error("fatal: customize is not set in configuration file.") + + +class NoCommitsFoundError(CommitizenException): + exit_code = ExitCode.NO_COMMITS_FOUND + + +class NoVersionSpecifiedError(CommitizenException): + exit_code = ExitCode.NO_VERSION_SPECIFIED + + +class NoPatternMapError(CommitizenException): + exit_code = ExitCode.NO_PATTERN_MAP + + +class CommitFailedError(CommitizenException): + exit_code = ExitCode.COMMIT_FAILED + + +class TagFailedError(CommitizenException): + exit_code = ExitCode.TAG_FAILED + + +class CurrentVersionNotFoundError(CommitizenException): + exit_code = ExitCode.CURRENT_VERSION_NOT_FOUND + + +class NoAnswersError(CommitizenException): + exit_code = ExitCode.NO_ANSWERS + + +class CommitError(CommitizenException): + exit_code = ExitCode.COMMIT_ERROR + + +class NoCommitBackupError(CommitizenException): + exit_code = ExitCode.NO_COMMIT_BACKUP + + +class NothingToCommitError(CommitizenException): + exit_code = ExitCode.NOTHING_TO_COMMIT + + +class CustomError(CommitizenException): + exit_code = ExitCode.CUSTOM_ERROR + + +class InvalidCommitMessageError(CommitizenException): + exit_code = ExitCode.INVALID_COMMIT_MSG + + +class NoRevisionError(CommitizenException): + exit_code = ExitCode.NO_REVISION diff --git a/commitizen/factory.py b/commitizen/factory.py index a589d8c205..b71dd98e91 100644 --- a/commitizen/factory.py +++ b/commitizen/factory.py @@ -1,7 +1,7 @@ from commitizen import BaseCommitizen, out from commitizen.config import BaseConfig from commitizen.cz import registry -from commitizen.error_codes import NO_COMMITIZEN_FOUND +from commitizen.exceptions import NoCommitizenFoundException def commiter_factory(config: BaseConfig) -> BaseCommitizen: @@ -15,6 +15,6 @@ def commiter_factory(config: BaseConfig) -> BaseCommitizen: f"Try running 'pip install {name}'\n" ) out.error(msg_error) - raise SystemExit(NO_COMMITIZEN_FOUND) + raise NoCommitizenFoundException(name) else: return _cz diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index a7c431720e..f08b0aff2f 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -3,7 +3,13 @@ import pytest from commitizen import cli, cmd, git -from commitizen.error_codes import CURRENT_VERSION_NOT_FOUND +from commitizen.exceptions import ( + CommitFailedError, + CurrentVersionNotFoundError, + NoCommitsFoundError, + NoPatternMapError, + NoVersionSpecifiedError, +) from tests.utils import create_file_and_commit @@ -73,7 +79,7 @@ def test_bump_on_git_with_hooks_no_verify_disabled(mocker, capsys): testargs = ["cz", "bump", "--yes"] mocker.patch.object(sys, "argv", testargs) - with pytest.raises(SystemExit): + with pytest.raises(CommitFailedError): cli.main() _, err = capsys.readouterr() @@ -111,7 +117,7 @@ def test_bump_when_bumpping_is_not_support(mocker, capsys, tmpdir): testargs = ["cz", "-n", "cz_jira", "bump", "--yes"] mocker.patch.object(sys, "argv", testargs) - with pytest.raises(SystemExit): + with pytest.raises(NoPatternMapError): cli.main() _, err = capsys.readouterr() @@ -122,7 +128,7 @@ def test_bump_when_bumpping_is_not_support(mocker, capsys, tmpdir): def test_bump_is_not_specify(mocker, capsys): mocker.patch.object(sys, "argv", ["cz", "bump"]) - with pytest.raises(SystemExit): + with pytest.raises(NoVersionSpecifiedError): cli.main() expected_error_message = ( @@ -140,7 +146,7 @@ def test_bump_when_no_new_commit(mocker, capsys): testargs = ["cz", "bump", "--yes"] mocker.patch.object(sys, "argv", testargs) - with pytest.raises(SystemExit): + with pytest.raises(NoCommitsFoundError): cli.main() expected_error_message = "[NO_COMMITS_FOUND]\n" "No new commits found." @@ -164,10 +170,9 @@ def test_bump_when_version_inconsistent_in_version_files( testargs = ["cz", "bump", "--yes", "--check-consistency"] mocker.patch.object(sys, "argv", testargs) - with pytest.raises(SystemExit) as excinfo: + with pytest.raises(CurrentVersionNotFoundError): cli.main() partial_expected_error_message = "Current version 0.1.0 is not found in" _, err = capsys.readouterr() - assert excinfo.value.code == CURRENT_VERSION_NOT_FOUND assert partial_expected_error_message in err diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index bfe2ab780f..539e88bde8 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -6,6 +6,7 @@ from commitizen import cli, git from commitizen.commands.changelog import Changelog +from commitizen.exceptions import NoCommitsFoundError from tests.utils import create_file_and_commit @@ -19,7 +20,7 @@ def test_changlog_on_empty_project(mocker): testargs = ["cz", "changelog", "--dry-run"] mocker.patch.object(sys, "argv", testargs) - with pytest.raises(SystemExit): + with pytest.raises(NoCommitsFoundError): cli.main() diff --git a/tests/commands/test_check_command.py b/tests/commands/test_check_command.py index bfa3d6bd88..e23194e1e2 100644 --- a/tests/commands/test_check_command.py +++ b/tests/commands/test_check_command.py @@ -4,6 +4,7 @@ import pytest from commitizen import cli, commands, git +from commitizen.exceptions import InvalidCommitMessageError, NoCommitsFoundError COMMIT_LOG = [ "refactor: A code change that neither fixes a bug nor adds a feature", @@ -52,7 +53,7 @@ def test_check_jira_fails(mocker, capsys): "commitizen.commands.check.open", mocker.mock_open(read_data="random message for J-2 #fake_command blah"), ) - with pytest.raises(SystemExit): + with pytest.raises(InvalidCommitMessageError): cli.main() _, err = capsys.readouterr() assert "commit validation: failed!" in err @@ -119,7 +120,7 @@ def test_check_conventional_commit_succeeds(mocker, capsys): def test_check_no_conventional_commit(config, mocker, tmpdir): - with pytest.raises(SystemExit): + with pytest.raises(InvalidCommitMessageError): error_mock = mocker.patch("commitizen.out.error") tempfile = tmpdir.join("temp_commit_file") @@ -181,7 +182,7 @@ def test_check_a_range_of_git_commits_and_failed(config, mocker): config=config, arguments={"rev_range": "HEAD~10..master"} ) - with pytest.raises(SystemExit): + with pytest.raises(InvalidCommitMessageError): check_cmd() error_mock.assert_called_once() @@ -198,7 +199,7 @@ def test_check_command_with_invalid_argment(args, config, capsys): def test_check_command_with_empty_range(config, mocker, capsys): check_cmd = commands.Check(config=config, arguments={"rev_range": "master..master"}) - with pytest.raises(SystemExit), pytest.warns(UserWarning) as record: + with pytest.raises(NoCommitsFoundError), pytest.warns(UserWarning) as record: check_cmd() assert record[0].message.args[0] == "No commit found with range: 'master..master'" diff --git a/tests/commands/test_commit_command.py b/tests/commands/test_commit_command.py index 97614696dd..12b453e1bf 100644 --- a/tests/commands/test_commit_command.py +++ b/tests/commands/test_commit_command.py @@ -4,6 +4,12 @@ from commitizen import cmd, commands from commitizen.cz.exceptions import CzException +from commitizen.exceptions import ( + CommitError, + CustomError, + NoCommitBackupError, + NothingToCommitError, +) @pytest.fixture @@ -37,7 +43,7 @@ def test_commit_retry_fails_no_backup(config, mocker): commit_mock = mocker.patch("commitizen.git.commit") commit_mock.return_value = cmd.Command("success", "", "", "") - with pytest.raises(SystemExit): + with pytest.raises(NoCommitBackupError): commands.Commit(config, {"retry": True})() @@ -57,7 +63,7 @@ def test_commit_retry_works(config, mocker): commit_mock.return_value = cmd.Command("", "error", "", "") error_mock = mocker.patch("commitizen.out.error") - with pytest.raises(SystemExit): + with pytest.raises(CommitError): commit_cmd = commands.Commit(config, {}) temp_file = commit_cmd.temp_file commit_cmd() @@ -91,7 +97,7 @@ def test_commit_command_with_dry_run_option(config, mocker): "footer": "", } - with pytest.raises(SystemExit): + with pytest.raises(NothingToCommitError): commit_cmd = commands.Commit(config, {"dry_run": True}) commit_cmd() @@ -100,12 +106,10 @@ def test_commit_when_nothing_to_commit(config, mocker): is_staging_clean_mock = mocker.patch("commitizen.git.is_staging_clean") is_staging_clean_mock.return_value = True - with pytest.raises(SystemExit) as err: + with pytest.raises(NothingToCommitError): commit_cmd = commands.Commit(config, {}) commit_cmd() - assert err.value.code == commands.commit.NOTHING_TO_COMMIT - @pytest.mark.usefixtures("staging_is_clean") def test_commit_when_customized_expected_raised(config, mocker, capsys): @@ -114,12 +118,10 @@ def test_commit_when_customized_expected_raised(config, mocker, capsys): prompt_mock = mocker.patch("questionary.prompt") prompt_mock.side_effect = _err - with pytest.raises(SystemExit) as err: + with pytest.raises(CustomError): commit_cmd = commands.Commit(config, {}) commit_cmd() - assert err.value.code == commands.commit.CUSTOM_ERROR - # Assert only the content in the formatted text captured = capsys.readouterr() assert "This is the root custom err" in captured.err diff --git a/tests/test_bump_update_version_in_files.py b/tests/test_bump_update_version_in_files.py index 4b48b0326c..1a89f8a89c 100644 --- a/tests/test_bump_update_version_in_files.py +++ b/tests/test_bump_update_version_in_files.py @@ -1,7 +1,7 @@ import pytest from commitizen import bump -from commitizen.error_codes import CURRENT_VERSION_NOT_FOUND +from commitizen.exceptions import CurrentVersionNotFoundError PYPROJECT = """ [tool.poetry] @@ -100,8 +100,7 @@ def test_file_version_inconsistent_error( ] old_version = "1.2.3" new_version = "2.0.0" - with pytest.raises(SystemExit) as excinfo: + with pytest.raises(CurrentVersionNotFoundError): bump.update_version_in_files( old_version, new_version, version_files, check_consistency=True ) - assert excinfo.value.code == CURRENT_VERSION_NOT_FOUND diff --git a/tests/test_conf.py b/tests/test_conf.py index 00dc4d40ad..b03475055a 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -4,6 +4,7 @@ import pytest from commitizen import config, defaults, git +from commitizen.exceptions import NotAGitProjectError PYPROJECT = """ [tool.commitizen] @@ -141,7 +142,7 @@ def test_find_git_project_root(tmpdir): def test_read_cfg_when_not_in_a_git_project(tmpdir): with tmpdir.as_cwd() as _: - with pytest.raises(SystemExit): + with pytest.raises(NotAGitProjectError): config.read_cfg() diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py index 23289d7d42..7d79e4cc61 100644 --- a/tests/test_cz_customize.py +++ b/tests/test_cz_customize.py @@ -2,7 +2,7 @@ from commitizen.config import BaseConfig, TomlConfig from commitizen.cz.customize import CustomizeCommitsCz -from commitizen.error_codes import MISSING_CONFIG +from commitizen.exceptions import MissingConfigError @pytest.fixture(scope="module") @@ -39,12 +39,10 @@ def config(): def test_initialize_cz_customize_failed(): - with pytest.raises(SystemExit) as excinfo: + with pytest.raises(MissingConfigError): config = BaseConfig() _ = CustomizeCommitsCz(config) - assert excinfo.value.code == MISSING_CONFIG - def test_bump_pattern(config): cz = CustomizeCommitsCz(config) diff --git a/tests/test_factory.py b/tests/test_factory.py index 5c5da7b139..5104f0e2ec 100644 --- a/tests/test_factory.py +++ b/tests/test_factory.py @@ -2,6 +2,7 @@ from commitizen import BaseCommitizen, defaults, factory from commitizen.config import BaseConfig +from commitizen.exceptions import NoCommitizenFoundException def test_factory(): @@ -14,5 +15,5 @@ def test_factory(): def test_factory_fails(): config = BaseConfig() config.settings.update({"name": "Nothing"}) - with pytest.raises(SystemExit): + with pytest.raises(NoCommitizenFoundException): factory.commiter_factory(config) From 4a1e975372b5dc32c5ab05d3bfad701fc0557061 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 6 Jun 2020 00:26:08 +0800 Subject: [PATCH 142/427] refactor: introduce DryRunExit, ExpectedExit, NoCommandFoundError, InvalidCommandArgumentError Instead of using SystemExit, we raise these error as CommitizenException --- commitizen/commands/bump.py | 6 +++-- commitizen/commands/changelog.py | 3 ++- commitizen/commands/check.py | 10 +++++--- commitizen/commands/commit.py | 3 ++- commitizen/exceptions.py | 29 +++++++++++++++++------- tests/commands/test_changelog_command.py | 6 ++--- tests/commands/test_check_command.py | 8 +++++-- tests/commands/test_commit_command.py | 3 ++- tests/test_cli.py | 5 ++-- 9 files changed, 50 insertions(+), 23 deletions(-) diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 57487bc5b2..92f6414fb7 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -8,6 +8,8 @@ from commitizen.config import BaseConfig from commitizen.exceptions import ( CommitFailedError, + DryRunExit, + ExpectedExit, NoCommitsFoundError, NoPatternMapError, NoVersionSpecifiedError, @@ -129,7 +131,7 @@ def __call__(self): # noqa: C901 # Do not perform operations over files or git. if dry_run: - raise SystemExit() + raise DryRunExit() bump.update_version_in_files( current_version, @@ -138,7 +140,7 @@ def __call__(self): # noqa: C901 check_consistency=self.check_consistency, ) if is_files_only: - raise SystemExit() + raise ExpectedExit() if self.changelog: changelog = Changelog( diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 92fa876764..a27f52de6d 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -6,6 +6,7 @@ from commitizen import changelog, factory, git, out from commitizen.config import BaseConfig from commitizen.exceptions import ( + DryRunExit, NoCommitsFoundError, NoPatternMapError, NoRevisionError, @@ -108,7 +109,7 @@ def __call__(self): if self.dry_run: out.write(changelog_out) - raise SystemExit(0) + raise DryRunExit() lines = [] if self.incremental and os.path.isfile(self.file_name): diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py index bb6724e2bf..436c41e4a7 100644 --- a/commitizen/commands/check.py +++ b/commitizen/commands/check.py @@ -5,7 +5,11 @@ from commitizen import factory, git, out from commitizen.config import BaseConfig -from commitizen.exceptions import InvalidCommitMessageError, NoCommitsFoundError +from commitizen.exceptions import ( + InvalidCommandArgumentError, + InvalidCommitMessageError, + NoCommitsFoundError, +) class Check: @@ -35,13 +39,13 @@ def _valid_command_argument(self): "See 'cz check -h' for more information" ) ) - raise SystemExit() + raise InvalidCommandArgumentError() def __call__(self): """Validate if commit messages follows the conventional pattern. Raises: - SystemExit: if the commit provided not follows the conventional pattern + InvalidCommitMessageError: if the commit provided not follows the conventional pattern """ commit_msgs = self._get_commit_messages() if not commit_msgs: diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index 7dc82f1242..f04bccc777 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -10,6 +10,7 @@ from commitizen.exceptions import ( CommitError, CustomError, + DryRunExit, NoAnswersError, NoCommitBackupError, NothingToCommitError, @@ -69,7 +70,7 @@ def __call__(self): out.info(f"\n{m}\n") if dry_run: - raise NothingToCommitError() + raise DryRunExit() c = git.commit(m) diff --git a/commitizen/exceptions.py b/commitizen/exceptions.py index c936583ebe..376b6a2590 100644 --- a/commitizen/exceptions.py +++ b/commitizen/exceptions.py @@ -4,34 +4,39 @@ class ExitCode(enum.IntEnum): + EXPECTED_EXIT = 0 NO_COMMITIZEN_FOUND = 1 - NOT_A_GIT_PROJECT = 2 - MISSING_CONFIG = 15 - NO_COMMITS_FOUND = 3 NO_VERSION_SPECIFIED = 4 NO_PATTERN_MAP = 5 COMMIT_FAILED = 6 TAG_FAILED = 7 - CURRENT_VERSION_NOT_FOUND = 17 - NO_ANSWERS = 8 COMMIT_ERROR = 9 NO_COMMIT_BACKUP = 10 NOTHING_TO_COMMIT = 11 CUSTOM_ERROR = 12 - + NO_COMMAND_FOUND = 13 INVALID_COMMIT_MSG = 14 - - # Changelog + MISSING_CONFIG = 15 NO_REVISION = 16 + CURRENT_VERSION_NOT_FOUND = 17 + INVALID_COMMAND_ARGUMENT = 18 class CommitizenException(Exception): pass +class ExpectedExit(CommitizenException): + exit_code = ExitCode.EXPECTED_EXIT + + +class DryRunExit(ExpectedExit): + pass + + class NoCommitizenFoundException(CommitizenException): exit_code = ExitCode.NO_COMMITIZEN_FOUND @@ -102,3 +107,11 @@ class InvalidCommitMessageError(CommitizenException): class NoRevisionError(CommitizenException): exit_code = ExitCode.NO_REVISION + + +class NoCommandFoundError(CommitizenException): + exit_code = ExitCode.NO_COMMAND_FOUND + + +class InvalidCommandArgumentError(CommitizenException): + exit_code = ExitCode.INVALID_COMMAND_ARGUMENT diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index 539e88bde8..7495d7cd4f 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -6,7 +6,7 @@ from commitizen import cli, git from commitizen.commands.changelog import Changelog -from commitizen.exceptions import NoCommitsFoundError +from commitizen.exceptions import DryRunExit, NoCommitsFoundError from tests.utils import create_file_and_commit @@ -40,7 +40,7 @@ def test_changlog_from_version_zero_point_two(mocker, capsys): testargs = ["cz", "changelog", "--start-rev", "0.2.0", "--dry-run"] mocker.patch.object(sys, "argv", testargs) - with pytest.raises(SystemExit): + with pytest.raises(DryRunExit): cli.main() out, _ = capsys.readouterr() @@ -55,7 +55,7 @@ def test_changlog_with_different_cz(mocker, capsys): testargs = ["cz", "-n", "cz_jira", "changelog", "--dry-run"] mocker.patch.object(sys, "argv", testargs) - with pytest.raises(SystemExit): + with pytest.raises(DryRunExit): cli.main() out, _ = capsys.readouterr() assert ( diff --git a/tests/commands/test_check_command.py b/tests/commands/test_check_command.py index e23194e1e2..a8113666d2 100644 --- a/tests/commands/test_check_command.py +++ b/tests/commands/test_check_command.py @@ -4,7 +4,11 @@ import pytest from commitizen import cli, commands, git -from commitizen.exceptions import InvalidCommitMessageError, NoCommitsFoundError +from commitizen.exceptions import ( + InvalidCommandArgumentError, + InvalidCommitMessageError, + NoCommitsFoundError, +) COMMIT_LOG = [ "refactor: A code change that neither fixes a bug nor adds a feature", @@ -191,7 +195,7 @@ def test_check_a_range_of_git_commits_and_failed(config, mocker): "args", [{"rev_range": "HEAD~10..master", "commit_msg_file": "some_file"}, {}] ) def test_check_command_with_invalid_argment(args, config, capsys): - with pytest.raises(SystemExit): + with pytest.raises(InvalidCommandArgumentError): commands.Check(config=config, arguments=args) _, err = capsys.readouterr() assert "One and only one argument is required for check command!" in err diff --git a/tests/commands/test_commit_command.py b/tests/commands/test_commit_command.py index 12b453e1bf..32da703616 100644 --- a/tests/commands/test_commit_command.py +++ b/tests/commands/test_commit_command.py @@ -7,6 +7,7 @@ from commitizen.exceptions import ( CommitError, CustomError, + DryRunExit, NoCommitBackupError, NothingToCommitError, ) @@ -97,7 +98,7 @@ def test_commit_command_with_dry_run_option(config, mocker): "footer": "", } - with pytest.raises(NothingToCommitError): + with pytest.raises(DryRunExit): commit_cmd = commands.Commit(config, {"dry_run": True}) commit_cmd() diff --git a/tests/test_cli.py b/tests/test_cli.py index 4275fa23ce..37bc4bff8d 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -4,13 +4,14 @@ from commitizen import cli from commitizen.__version__ import __version__ +from commitizen.exceptions import ExpectedExit, NoCommandFoundError def test_sysexit_no_argv(mocker, capsys): testargs = ["cz"] mocker.patch.object(sys, "argv", testargs) - with pytest.raises(SystemExit): + with pytest.raises(ExpectedExit): cli.main() out, _ = capsys.readouterr() assert out.startswith("usage") @@ -20,7 +21,7 @@ def test_cz_with_arg_but_without_command(mocker, capsys): testargs = ["cz", "--name", "cz_jira"] mocker.patch.object(sys, "argv", testargs) - with pytest.raises(SystemExit): + with pytest.raises(NoCommandFoundError): cli.main() _, err = capsys.readouterr() assert "Command is required" in err From 68b7d6976c09f1083b74ced3b6d92e19c31dc0e2 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 6 Jun 2020 00:26:59 +0800 Subject: [PATCH 143/427] refactor(cli): do not show traceback if the raised exception is CommitizenException --- commitizen/cli.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index eb0ce869eb..5f1d87fff4 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -6,7 +6,7 @@ from decli import cli from commitizen import commands, config, out -from commitizen.exceptions import CommitizenException +from commitizen.exceptions import CommitizenException, ExpectedExit, NoCommandFoundError logger = logging.getLogger(__name__) data = { @@ -242,9 +242,10 @@ def commitizen_excepthook(type, value, tracekback): - original_excepthook(type, value, tracekback) if isinstance(value, CommitizenException): sys.exit(value.exit_code) + else: + original_excepthook(type, value, tracekback) sys.excepthook = commitizen_excepthook @@ -257,14 +258,14 @@ def main(): # Show help if no arg provided if len(sys.argv) == 1: parser.print_help(sys.stderr) - raise SystemExit() + raise ExpectedExit() # This is for the command required constraint in 2.0 try: args = parser.parse_args() except TypeError: out.error("Command is required") - raise SystemExit() + raise NoCommandFoundError() if args.name: conf.update({"name": args.name}) @@ -297,4 +298,8 @@ def main(): args.func(conf, vars(args))() except AttributeError: out.error("Command is required") - raise SystemExit() + raise NoCommandFoundError() + + +if __name__ == "__main__": + main() From f502e080b883ad01c3c9cde9a380f75d0865145d Mon Sep 17 00:00:00 2001 From: David Arnold <dar@xoe.solutions> Date: Tue, 9 Jun 2020 20:12:57 -0500 Subject: [PATCH 144/427] docs(customization): Update customization.md fixes #202 --- docs/customization.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/customization.md b/docs/customization.md index b74d086957..8211e9120a 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -226,7 +226,8 @@ This is customized info [[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."}] +# choices = ["feature", "fix"] # short version message = "Select the type of change you are committing" [[tool.commitizen.customize.questions]] @@ -244,7 +245,7 @@ message = "Do you want to add body message in commit?" | Parameter | Type | Default | Description | | ------------------ | ------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `question` | `dict` | `None` | Questions regarding the commit message. Detailed below. | +| `questions` | `dict` | `None` | Questions regarding the commit message. Detailed below. | | `message_template` | `str` | `None` | The template for generating message from the given answers. `message_template` should either follow 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`. | @@ -253,13 +254,13 @@ message = "Do you want to add body message in commit?" | `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 +#### Detailed `questions` content | Parameter | Type | Default | Description | | --------- | ------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `type` | `str` | `None` | The type of questions. Valid type: `list`, `input` and etc. [See More](https://github.com/tmbo/questionary#different-question-types) | | `name` | `str` | `None` | The key for the value answered by user. It's used in `message_template` | | `message` | `str` | `None` | Detail description for the question. | -| `choices` | `list` | `None` | (OPTIONAL) The choices when `type = 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."}]`) | +| `choices` | `list` | `None` | (OPTIONAL) The choices when `type = list`. Either use a list of values or a list of dicitionaries with `name` and `value` keys. See examples above. | | `default` | `Any` | `None` | (OPTIONAL) The default value for this question. | | `filter` | `str` | `None` | (Optional) Validator for user's answer. **(Work in Progress)** | From fa681afbc1ff63c37223220162b075903a15a3e7 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 10 Jun 2020 01:13:41 +0000 Subject: [PATCH 145/427] =?UTF-8?q?bump:=20version=201.22.2=20=E2=86=92=20?= =?UTF-8?q?1.22.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 ++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 111c473238..b360ee97dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## v1.22.3 (2020-06-10) + ## v1.22.2 (2020-05-29) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index cbb09c4039..90495751d4 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.22.2" +__version__ = "1.22.3" diff --git a/pyproject.toml b/pyproject.toml index 27f2e4a00c..f39a6a56d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.22.2" +version = "1.22.3" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.22.2" +version = "1.22.3" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 016fba7eed9f23ff987114a7d18d65eb32f84d3a Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 14 Jun 2020 12:23:43 +0800 Subject: [PATCH 146/427] test(bump): add test case for --files-only option --- tests/commands/test_bump_command.py | 39 ++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index f08b0aff2f..4d46642902 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -4,6 +4,7 @@ from commitizen import cli, cmd, git from commitizen.exceptions import ( + ExpectedExit, CommitFailedError, CurrentVersionNotFoundError, NoCommitsFoundError, @@ -104,12 +105,8 @@ def test_bump_on_git_with_hooks_no_verify_enabled(mocker): assert tag_exists is True -def test_bump_when_bumpping_is_not_support(mocker, capsys, tmpdir): - with tmpdir.as_cwd(): - with open("./pyproject.toml", "w") as f: - f.write("[tool.commitizen]\n" 'version="0.1.0"') - - cmd.run("git init") +def test_bump_when_bumpping_is_not_support(mocker, capsys, tmp_commitizen_project): + with tmp_commitizen_project.as_cwd(): create_file_and_commit( "feat: new user interface\n\nBREAKING CHANGE: age is no longer supported" ) @@ -176,3 +173,33 @@ def test_bump_when_version_inconsistent_in_version_files( partial_expected_error_message = "Current version 0.1.0 is not found in" _, err = capsys.readouterr() assert partial_expected_error_message in err + + +def test_bump_files_only(mocker, tmp_commitizen_project): + with tmp_commitizen_project.as_cwd(): + tmp_version_file = tmp_commitizen_project.join("__version__.py") + tmp_version_file.write("0.1.0") + tmp_commitizen_cfg_file = tmp_commitizen_project.join("pyproject.toml") + tmp_commitizen_cfg_file.write( + f"{tmp_commitizen_cfg_file.read()}\n" + f'version_files = ["{str(tmp_version_file)}"]' + ) + + create_file_and_commit("feat: new user interface") + testargs = ["cz", "bump", "--yes"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + tag_exists = git.tag_exist("0.2.0") + assert tag_exists is True + + create_file_and_commit("feat: another new feature") + testargs = ["cz", "bump", "--yes", "--files-only"] + mocker.patch.object(sys, "argv", testargs) + with pytest.raises(ExpectedExit): + cli.main() + + tag_exists = git.tag_exist("0.3.0") + assert tag_exists is False + + with open(tmp_version_file, "r") as f: + assert "0.3.0" in f.read() From 168c9f0a1f62c76ea421a7f31885105c50d89256 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 14 Jun 2020 12:27:17 +0800 Subject: [PATCH 147/427] style(tests): fix function name typo --- tests/commands/test_changelog_command.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index 7495d7cd4f..53fe9a1af0 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -16,7 +16,7 @@ def changelog_path() -> str: @pytest.mark.usefixtures("tmp_commitizen_project") -def test_changlog_on_empty_project(mocker): +def test_changelog_on_empty_project(mocker): testargs = ["cz", "changelog", "--dry-run"] mocker.patch.object(sys, "argv", testargs) @@ -25,7 +25,7 @@ def test_changlog_on_empty_project(mocker): @pytest.mark.usefixtures("tmp_commitizen_project") -def test_changlog_from_version_zero_point_two(mocker, capsys): +def test_changelog_from_version_zero_point_two(mocker, capsys): create_file_and_commit("feat: new file") create_file_and_commit("refactor: not in changelog") @@ -48,7 +48,7 @@ def test_changlog_from_version_zero_point_two(mocker, capsys): @pytest.mark.usefixtures("tmp_commitizen_project") -def test_changlog_with_different_cz(mocker, capsys): +def test_changelog_with_different_cz(mocker, capsys): create_file_and_commit("JRA-34 #comment corrected indent issue") create_file_and_commit("JRA-35 #time 1w 2d 4h 30m Total work logged") @@ -65,7 +65,7 @@ def test_changlog_with_different_cz(mocker, capsys): @pytest.mark.usefixtures("tmp_commitizen_project") -def test_changlog_from_start(mocker, capsys, changelog_path): +def test_changelog_from_start(mocker, capsys, changelog_path): create_file_and_commit("feat: new file") create_file_and_commit("refactor: is in changelog") create_file_and_commit("Merge into master") @@ -84,7 +84,7 @@ def test_changlog_from_start(mocker, capsys, changelog_path): @pytest.mark.usefixtures("tmp_commitizen_project") -def test_changlog_replacing_unreleased_using_incremental( +def test_changelog_replacing_unreleased_using_incremental( mocker, capsys, changelog_path ): create_file_and_commit("feat: add new output") @@ -118,7 +118,7 @@ def test_changlog_replacing_unreleased_using_incremental( @pytest.mark.usefixtures("tmp_commitizen_project") -def test_changlog_is_persisted_using_incremental(mocker, capsys, changelog_path): +def test_changelog_is_persisted_using_incremental(mocker, capsys, changelog_path): create_file_and_commit("feat: add new output") create_file_and_commit("fix: output glitch") @@ -155,7 +155,7 @@ def test_changlog_is_persisted_using_incremental(mocker, capsys, changelog_path) @pytest.mark.usefixtures("tmp_commitizen_project") -def test_changlog_incremental_angular_sample(mocker, capsys, changelog_path): +def test_changelog_incremental_angular_sample(mocker, capsys, changelog_path): with open(changelog_path, "w") as f: f.write( "# [10.0.0-next.3](https://github.com/angular/angular/compare/10.0.0-next.2...10.0.0-next.3) (2020-04-22)\n" @@ -213,7 +213,7 @@ def test_changlog_incremental_angular_sample(mocker, capsys, changelog_path): @pytest.mark.usefixtures("tmp_commitizen_project") -def test_changlog_incremental_keep_a_changelog_sample(mocker, capsys, changelog_path): +def test_changelog_incremental_keep_a_changelog_sample(mocker, capsys, changelog_path): with open(changelog_path, "w") as f: f.write(KEEP_A_CHANGELOG) create_file_and_commit("irrelevant commit") @@ -240,7 +240,7 @@ def test_changlog_incremental_keep_a_changelog_sample(mocker, capsys, changelog_ @pytest.mark.usefixtures("tmp_commitizen_project") -def test_changlog_hook(mocker, config): +def test_changelog_hook(mocker, config): changelog_hook_mock = mocker.Mock() changelog_hook_mock.return_value = "cool changelog hook" @@ -249,7 +249,7 @@ def test_changlog_hook(mocker, config): create_file_and_commit("Merge into master") changelog = Changelog( - config, {"unreleased_version": None, "incremental": True, "dry_run": False}, + config, {"unreleased_version": None, "incremental": True, "dry_run": False} ) mocker.patch.object(changelog.cz, "changelog_hook", changelog_hook_mock) changelog() @@ -261,7 +261,7 @@ def test_changlog_hook(mocker, config): @pytest.mark.usefixtures("tmp_commitizen_project") -def test_changlog_multiple_incremental_do_not_add_new_lines( +def test_changelog_multiple_incremental_do_not_add_new_lines( mocker, capsys, changelog_path ): """Test for bug https://github.com/commitizen-tools/commitizen/issues/192""" From ad9d803773f0b0a1a9d5212a072d46f310143404 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 14 Jun 2020 12:33:32 +0800 Subject: [PATCH 148/427] test(bump): add test case for dry run --- tests/commands/test_bump_command.py | 82 +++++++++++++++++------------ 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index 4d46642902..46252ea57d 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -4,9 +4,10 @@ from commitizen import cli, cmd, git from commitizen.exceptions import ( - ExpectedExit, CommitFailedError, CurrentVersionNotFoundError, + DryRunExit, + ExpectedExit, NoCommitsFoundError, NoPatternMapError, NoVersionSpecifiedError, @@ -106,19 +107,18 @@ def test_bump_on_git_with_hooks_no_verify_enabled(mocker): def test_bump_when_bumpping_is_not_support(mocker, capsys, tmp_commitizen_project): - with tmp_commitizen_project.as_cwd(): - create_file_and_commit( - "feat: new user interface\n\nBREAKING CHANGE: age is no longer supported" - ) + create_file_and_commit( + "feat: new user interface\n\nBREAKING CHANGE: age is no longer supported" + ) - testargs = ["cz", "-n", "cz_jira", "bump", "--yes"] - mocker.patch.object(sys, "argv", testargs) + testargs = ["cz", "-n", "cz_jira", "bump", "--yes"] + mocker.patch.object(sys, "argv", testargs) - with pytest.raises(NoPatternMapError): - cli.main() + with pytest.raises(NoPatternMapError): + cli.main() - _, err = capsys.readouterr() - assert "'cz_jira' rule does not support bump" in err + _, err = capsys.readouterr() + assert "'cz_jira' rule does not support bump" in err @pytest.mark.usefixtures("tmp_git_project") @@ -176,30 +176,44 @@ def test_bump_when_version_inconsistent_in_version_files( def test_bump_files_only(mocker, tmp_commitizen_project): - with tmp_commitizen_project.as_cwd(): - tmp_version_file = tmp_commitizen_project.join("__version__.py") - tmp_version_file.write("0.1.0") - tmp_commitizen_cfg_file = tmp_commitizen_project.join("pyproject.toml") - tmp_commitizen_cfg_file.write( - f"{tmp_commitizen_cfg_file.read()}\n" - f'version_files = ["{str(tmp_version_file)}"]' - ) - - create_file_and_commit("feat: new user interface") - testargs = ["cz", "bump", "--yes"] - mocker.patch.object(sys, "argv", testargs) + tmp_version_file = tmp_commitizen_project.join("__version__.py") + tmp_version_file.write("0.1.0") + tmp_commitizen_cfg_file = tmp_commitizen_project.join("pyproject.toml") + tmp_commitizen_cfg_file.write( + f"{tmp_commitizen_cfg_file.read()}\n" + f'version_files = ["{str(tmp_version_file)}"]' + ) + + create_file_and_commit("feat: new user interface") + testargs = ["cz", "bump", "--yes"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + tag_exists = git.tag_exist("0.2.0") + assert tag_exists is True + + create_file_and_commit("feat: another new feature") + testargs = ["cz", "bump", "--yes", "--files-only"] + mocker.patch.object(sys, "argv", testargs) + with pytest.raises(ExpectedExit): cli.main() - tag_exists = git.tag_exist("0.2.0") - assert tag_exists is True - create_file_and_commit("feat: another new feature") - testargs = ["cz", "bump", "--yes", "--files-only"] - mocker.patch.object(sys, "argv", testargs) - with pytest.raises(ExpectedExit): - cli.main() + tag_exists = git.tag_exist("0.3.0") + assert tag_exists is False + + with open(tmp_version_file, "r") as f: + assert "0.3.0" in f.read() - tag_exists = git.tag_exist("0.3.0") - assert tag_exists is False - with open(tmp_version_file, "r") as f: - assert "0.3.0" in f.read() +def test_bump_dry_run(mocker, capsys, tmp_commitizen_project): + create_file_and_commit("feat: new file") + + testargs = ["cz", "bump", "--yes", "--dry-run"] + mocker.patch.object(sys, "argv", testargs) + with pytest.raises(DryRunExit): + cli.main() + + out, _ = capsys.readouterr() + assert "0.2.0" in out + + tag_exists = git.tag_exist("0.2.0") + assert tag_exists is False From ffb6dde7006e163a8ffd44d98f0597b3a894b4f5 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 14 Jun 2020 12:36:21 +0800 Subject: [PATCH 149/427] refactor(exception): implement message handling mechanism for CommitizenException --- commitizen/cli.py | 2 ++ commitizen/exceptions.py | 23 ++++++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index 5f1d87fff4..91bf0108ad 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -243,6 +243,8 @@ def commitizen_excepthook(type, value, tracekback): if isinstance(value, CommitizenException): + if value.message: + value.output_method(value.message) sys.exit(value.exit_code) else: original_excepthook(type, value, tracekback) diff --git a/commitizen/exceptions.py b/commitizen/exceptions.py index 376b6a2590..8ba836031c 100644 --- a/commitizen/exceptions.py +++ b/commitizen/exceptions.py @@ -26,7 +26,18 @@ class ExitCode(enum.IntEnum): class CommitizenException(Exception): - pass + def __init__(self, *args, **kwargs): + self.output_method = kwargs.get("output_method") or out.error + self.exit_code = self.__class__.exit_code + if args: + self.message = args[0] + elif hasattr(self.__class__, "message"): + self.message = self.__class__.message + else: + self.message = "" + + def __str__(self): + return self.message class ExpectedExit(CommitizenException): @@ -43,18 +54,12 @@ class NoCommitizenFoundException(CommitizenException): class NotAGitProjectError(CommitizenException): exit_code = ExitCode.NOT_A_GIT_PROJECT - - def __init__(self, *args, **kwargs): - out.error( - "fatal: not a git repository (or any of the parent directories): .git" - ) + message = "fatal: not a git repository (or any of the parent directories): .git" class MissingConfigError(CommitizenException): exit_code = ExitCode.MISSING_CONFIG - - def __init__(self, *args, **kwargs): - out.error("fatal: customize is not set in configuration file.") + message = "fatal: customize is not set in configuration file." class NoCommitsFoundError(CommitizenException): From 4bfff4d078389d47040f8825c2cca81aafa2fe6f Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 14 Jun 2020 16:48:12 +0800 Subject: [PATCH 150/427] refactor(exception): move output message related to exception into exception --- commitizen/bump.py | 4 +-- commitizen/cli.py | 4 +-- commitizen/commands/bump.py | 19 ++++------ commitizen/commands/changelog.py | 7 ++-- commitizen/commands/check.py | 10 ++---- commitizen/commands/commit.py | 7 ++-- commitizen/commands/init.py | 7 ++-- commitizen/exceptions.py | 12 +++++++ commitizen/factory.py | 5 ++- tests/commands/test_bump_command.py | 41 ++++++++-------------- tests/commands/test_changelog_command.py | 4 ++- tests/commands/test_check_command.py | 22 ++++++------ tests/commands/test_commit_command.py | 13 ++++--- tests/test_bump_update_version_in_files.py | 9 ++++- tests/test_cli.py | 7 ++-- tests/test_conf.py | 4 ++- tests/test_cz_customize.py | 4 ++- tests/test_factory.py | 4 ++- 18 files changed, 89 insertions(+), 94 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index f18cf97567..e4120eb5b1 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -6,7 +6,6 @@ from packaging.version import Version -from commitizen import out from commitizen.defaults import ( MAJOR, MINOR, @@ -162,12 +161,11 @@ def update_version_in_files( file_content.append(line) if check_consistency and not current_version_found: - out.error( + raise CurrentVersionNotFoundError( f"Current version {current_version} is not found in {location}.\n" "The version defined in commitizen configuration and the ones in " "version_files are possibly inconsistent." ) - raise CurrentVersionNotFoundError() # Write the file out again with open(filepath, "w") as file: diff --git a/commitizen/cli.py b/commitizen/cli.py index 91bf0108ad..2b6f9648c1 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -5,7 +5,7 @@ from decli import cli -from commitizen import commands, config, out +from commitizen import commands, config from commitizen.exceptions import CommitizenException, ExpectedExit, NoCommandFoundError logger = logging.getLogger(__name__) @@ -266,7 +266,6 @@ def main(): try: args = parser.parse_args() except TypeError: - out.error("Command is required") raise NoCommandFoundError() if args.name: @@ -299,7 +298,6 @@ def main(): try: args.func(conf, vars(args))() except AttributeError: - out.error("Command is required") raise NoCommandFoundError() diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 92f6414fb7..1d37a9e4c1 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -58,8 +58,9 @@ def find_increment(self, commits: List[git.GitCommit]) -> 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.settings['name']}' rule does not support bump") - raise NoPatternMapError() + raise NoPatternMapError( + f"'{self.config.settings['name']}' rule does not support bump" + ) increment = bump.find_increment( commits, regex=bump_pattern, increments_map=bump_map ) @@ -70,11 +71,6 @@ def __call__(self): # noqa: C901 try: current_version_instance: Version = Version(self.bump_settings["version"]) except TypeError: - out.error( - "[NO_VERSION_SPECIFIED]\n" - "Check if current version is specified in config file, like:\n" - "version = 0.4.3\n" - ) raise NoVersionSpecifiedError() # Initialize values from sources (conf) @@ -103,8 +99,7 @@ def __call__(self): # noqa: C901 # No commits, there is no need to create an empty tag. # Unless we previously had a prerelease. if not commits and not current_version_instance.is_prerelease: - out.error("[NO_COMMITS_FOUND]\n" "No new commits found.") - raise NoCommitsFoundError() + raise NoCommitsFoundError("[NO_COMMITS_FOUND]\n" "No new commits found.") if increment is None: increment = self.find_increment(commits) @@ -156,12 +151,10 @@ def __call__(self): # noqa: C901 self.config.set_key("version", new_version.public) c = git.commit(message, args=self._get_commit_args()) if c.err: - out.error('git.commit error: "{}"'.format(c.err.strip())) - raise CommitFailedError() + raise CommitFailedError(f'git.commit error: "{c.err.strip()}"') c = git.tag(new_tag_version) if c.err: - out.error(c.err) - raise TagFailedError() + raise TagFailedError(c.err) out.success("Done!") def _get_commit_args(self): diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index a27f52de6d..bfe6776dde 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -73,12 +73,10 @@ def __call__(self): Callable ] = self.cz.changelog_message_builder_hook changelog_hook: Optional[Callable] = self.cz.changelog_hook - if not changelog_pattern or not commit_parser: - out.error( + raise NoPatternMapError( f"'{self.config.settings['name']}' rule does not support changelog" ) - raise NoPatternMapError() tags = git.get_tags() if not tags: @@ -92,8 +90,7 @@ def __call__(self): commits = git.get_commits(start=start_rev, args="--author-date-order") if not commits: - out.error("No commits found") - raise NoCommitsFoundError() + raise NoCommitsFoundError("No commits found") tree = changelog.generate_tree_from_commits( commits, diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py index 436c41e4a7..764beb5a03 100644 --- a/commitizen/commands/check.py +++ b/commitizen/commands/check.py @@ -1,6 +1,5 @@ import os import re -import warnings from typing import Dict, Optional from commitizen import factory, git, out @@ -33,13 +32,12 @@ def __init__(self, config: BaseConfig, arguments: Dict[str, str], cwd=os.getcwd( def _valid_command_argument(self): if bool(self.commit_msg_file) is bool(self.rev_range): - out.error( + raise InvalidCommandArgumentError( ( "One and only one argument is required for check command! " "See 'cz check -h' for more information" ) ) - raise InvalidCommandArgumentError() def __call__(self): """Validate if commit messages follows the conventional pattern. @@ -49,19 +47,17 @@ def __call__(self): """ commit_msgs = self._get_commit_messages() if not commit_msgs: - warnings.warn(f"No commit found with range: '{self.rev_range}'") - raise NoCommitsFoundError() + raise NoCommitsFoundError(f"No commit found with range: '{self.rev_range}'") pattern = self.cz.schema_pattern() for commit_msg in commit_msgs: if not Check.validate_commit_message(commit_msg, pattern): - out.error( + raise InvalidCommitMessageError( "commit validation: failed!\n" "please enter a commit message in the commitizen format.\n" f"commit: {commit_msg}\n" f"pattern: {pattern}" ) - raise InvalidCommitMessageError() out.success("Commit validation: successful!") def _get_commit_messages(self): diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index f04bccc777..9f1d7ed57e 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -29,7 +29,6 @@ def __init__(self, config: BaseConfig, arguments: dict): def read_backup_message(self) -> str: # Check the commit backup file exists if not os.path.isfile(self.temp_file): - out.error("No commit backup found") raise NoCommitBackupError() # Read commit message from backup @@ -45,8 +44,7 @@ def prompt_commit_questions(self) -> str: except ValueError as err: root_err = err.__context__ if isinstance(root_err, CzException): - out.error(root_err.__str__()) - raise CustomError() + raise CustomError(root_err.__str__()) raise err if not answers: @@ -57,8 +55,7 @@ def __call__(self): 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 NothingToCommitError() + raise NothingToCommitError("No files added to staging!") retry: bool = self.arguments.get("retry") diff --git a/commitizen/commands/init.py b/commitizen/commands/init.py index c8ab4fb97e..83a30f86a7 100644 --- a/commitizen/commands/init.py +++ b/commitizen/commands/init.py @@ -2,6 +2,7 @@ from packaging.version import Version from commitizen import factory, out +from commitizen.exceptions import ExpectedExit, NoAnswersError from commitizen.config import BaseConfig, IniConfig, TomlConfig from commitizen.cz import registry from commitizen.defaults import long_term_support_config_files @@ -79,8 +80,7 @@ def _ask_tag(self) -> str: ).ask() if not latest_tag: - out.error("Tag is required!") - raise SystemExit() + raise NoAnswersError("Tag is required!") return latest_tag def _ask_tag_format(self, latest_tag) -> str: @@ -103,8 +103,7 @@ def _ask_tag_format(self, latest_tag) -> str: def _update_config_file(self, values): if not values: - out.write("The configuration were all set. Nothing to add.") - raise SystemExit() + raise ExpectedExit("The configuration were all set. Nothing to add.") for key, value in values.items(): self.config.set_key(key, value) diff --git a/commitizen/exceptions.py b/commitizen/exceptions.py index 8ba836031c..b1ea255f63 100644 --- a/commitizen/exceptions.py +++ b/commitizen/exceptions.py @@ -43,6 +43,11 @@ def __str__(self): class ExpectedExit(CommitizenException): exit_code = ExitCode.EXPECTED_EXIT + def __init__(self, *args, **kwargs): + output_method = kwargs.get("output_method") or out.write + kwargs["output_method"] = output_method + super().__init__(*args, **kwargs) + class DryRunExit(ExpectedExit): pass @@ -68,6 +73,11 @@ class NoCommitsFoundError(CommitizenException): class NoVersionSpecifiedError(CommitizenException): exit_code = ExitCode.NO_VERSION_SPECIFIED + message = ( + "[NO_VERSION_SPECIFIED]\n" + "Check if current version is specified in config file, like:\n" + "version = 0.4.3\n" + ) class NoPatternMapError(CommitizenException): @@ -96,6 +106,7 @@ class CommitError(CommitizenException): class NoCommitBackupError(CommitizenException): exit_code = ExitCode.NO_COMMIT_BACKUP + message = "No commit backup found" class NothingToCommitError(CommitizenException): @@ -116,6 +127,7 @@ class NoRevisionError(CommitizenException): class NoCommandFoundError(CommitizenException): exit_code = ExitCode.NO_COMMAND_FOUND + message = "Command is required" class InvalidCommandArgumentError(CommitizenException): diff --git a/commitizen/factory.py b/commitizen/factory.py index b71dd98e91..09af5fd0f7 100644 --- a/commitizen/factory.py +++ b/commitizen/factory.py @@ -1,4 +1,4 @@ -from commitizen import BaseCommitizen, out +from commitizen import BaseCommitizen from commitizen.config import BaseConfig from commitizen.cz import registry from commitizen.exceptions import NoCommitizenFoundException @@ -14,7 +14,6 @@ def commiter_factory(config: BaseConfig) -> BaseCommitizen: "The committer has not been found in the system.\n\n" f"Try running 'pip install {name}'\n" ) - out.error(msg_error) - raise NoCommitizenFoundException(name) + raise NoCommitizenFoundException(msg_error) else: return _cz diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index 46252ea57d..fd3089eed8 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -69,7 +69,7 @@ def test_bump_command(mocker): @pytest.mark.usefixtures("tmp_commitizen_project") -def test_bump_on_git_with_hooks_no_verify_disabled(mocker, capsys): +def test_bump_on_git_with_hooks_no_verify_disabled(mocker): cmd.run("mkdir .git/hooks") with open(".git/hooks/pre-commit", "w") as f: f.write("#!/usr/bin/env bash\n" 'echo "0.1.0"') @@ -81,11 +81,10 @@ def test_bump_on_git_with_hooks_no_verify_disabled(mocker, capsys): testargs = ["cz", "bump", "--yes"] mocker.patch.object(sys, "argv", testargs) - with pytest.raises(CommitFailedError): + with pytest.raises(CommitFailedError) as excinfo: cli.main() - _, err = capsys.readouterr() - assert 'git.commit error: "0.1.0"' in err + assert 'git.commit error: "0.1.0"' in str(excinfo.value) @pytest.mark.usefixtures("tmp_commitizen_project") @@ -106,7 +105,7 @@ def test_bump_on_git_with_hooks_no_verify_enabled(mocker): assert tag_exists is True -def test_bump_when_bumpping_is_not_support(mocker, capsys, tmp_commitizen_project): +def test_bump_when_bumpping_is_not_support(mocker, tmp_commitizen_project): create_file_and_commit( "feat: new user interface\n\nBREAKING CHANGE: age is no longer supported" ) @@ -114,45 +113,36 @@ def test_bump_when_bumpping_is_not_support(mocker, capsys, tmp_commitizen_projec testargs = ["cz", "-n", "cz_jira", "bump", "--yes"] mocker.patch.object(sys, "argv", testargs) - with pytest.raises(NoPatternMapError): + with pytest.raises(NoPatternMapError) as excinfo: cli.main() - _, err = capsys.readouterr() - assert "'cz_jira' rule does not support bump" in err + assert "'cz_jira' rule does not support bump" in str(excinfo.value) @pytest.mark.usefixtures("tmp_git_project") -def test_bump_is_not_specify(mocker, capsys): +def test_bump_when_version_is_not_specify(mocker): mocker.patch.object(sys, "argv", ["cz", "bump"]) - with pytest.raises(NoVersionSpecifiedError): + with pytest.raises(NoVersionSpecifiedError) as excinfo: cli.main() - expected_error_message = ( - "[NO_VERSION_SPECIFIED]\n" - "Check if current version is specified in config file, like:\n" - "version = 0.4.3\n" - ) - - _, err = capsys.readouterr() - assert expected_error_message in err + assert NoVersionSpecifiedError.message in str(excinfo.value) @pytest.mark.usefixtures("tmp_commitizen_project") -def test_bump_when_no_new_commit(mocker, capsys): +def test_bump_when_no_new_commit(mocker): testargs = ["cz", "bump", "--yes"] mocker.patch.object(sys, "argv", testargs) - with pytest.raises(NoCommitsFoundError): + with pytest.raises(NoCommitsFoundError) as excinfo: cli.main() expected_error_message = "[NO_COMMITS_FOUND]\n" "No new commits found." - _, err = capsys.readouterr() - assert expected_error_message in err + assert expected_error_message in str(excinfo.value) def test_bump_when_version_inconsistent_in_version_files( - tmp_commitizen_project, mocker, capsys + tmp_commitizen_project, mocker ): tmp_version_file = tmp_commitizen_project.join("__version__.py") tmp_version_file.write("100.999.10000") @@ -167,12 +157,11 @@ def test_bump_when_version_inconsistent_in_version_files( testargs = ["cz", "bump", "--yes", "--check-consistency"] mocker.patch.object(sys, "argv", testargs) - with pytest.raises(CurrentVersionNotFoundError): + with pytest.raises(CurrentVersionNotFoundError) as excinfo: cli.main() partial_expected_error_message = "Current version 0.1.0 is not found in" - _, err = capsys.readouterr() - assert partial_expected_error_message in err + assert partial_expected_error_message in str(excinfo.value) def test_bump_files_only(mocker, tmp_commitizen_project): diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index 53fe9a1af0..0500ed0da0 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -20,9 +20,11 @@ def test_changelog_on_empty_project(mocker): testargs = ["cz", "changelog", "--dry-run"] mocker.patch.object(sys, "argv", testargs) - with pytest.raises(NoCommitsFoundError): + with pytest.raises(NoCommitsFoundError) as excinfo: cli.main() + assert "No commits found" in str(excinfo) + @pytest.mark.usefixtures("tmp_commitizen_project") def test_changelog_from_version_zero_point_two(mocker, capsys): diff --git a/tests/commands/test_check_command.py b/tests/commands/test_check_command.py index a8113666d2..5ea824af33 100644 --- a/tests/commands/test_check_command.py +++ b/tests/commands/test_check_command.py @@ -50,17 +50,16 @@ def _build_fake_git_commits(commit_msgs: List[str]) -> List[git.GitCommit]: return [git.GitCommit("test_rev", commit_msg) for commit_msg in commit_msgs] -def test_check_jira_fails(mocker, capsys): +def test_check_jira_fails(mocker): testargs = ["cz", "-n", "cz_jira", "check", "--commit-msg-file", "some_file"] mocker.patch.object(sys, "argv", testargs) mocker.patch( "commitizen.commands.check.open", mocker.mock_open(read_data="random message for J-2 #fake_command blah"), ) - with pytest.raises(InvalidCommitMessageError): + with pytest.raises(InvalidCommitMessageError) as excinfo: cli.main() - _, err = capsys.readouterr() - assert "commit validation: failed!" in err + assert "commit validation: failed!" in str(excinfo.value) def test_check_jira_command_after_issue_one_space(mocker, capsys): @@ -194,16 +193,17 @@ def test_check_a_range_of_git_commits_and_failed(config, mocker): @pytest.mark.parametrize( "args", [{"rev_range": "HEAD~10..master", "commit_msg_file": "some_file"}, {}] ) -def test_check_command_with_invalid_argment(args, config, capsys): - with pytest.raises(InvalidCommandArgumentError): +def test_check_command_with_invalid_argment(args, config): + with pytest.raises(InvalidCommandArgumentError) as excinfo: commands.Check(config=config, arguments=args) - _, err = capsys.readouterr() - assert "One and only one argument is required for check command!" in err + assert "One and only one argument is required for check command!" in str( + excinfo.value + ) -def test_check_command_with_empty_range(config, mocker, capsys): +def test_check_command_with_empty_range(config, mocker): check_cmd = commands.Check(config=config, arguments={"rev_range": "master..master"}) - with pytest.raises(NoCommitsFoundError), pytest.warns(UserWarning) as record: + with pytest.raises(NoCommitsFoundError) as excinfo: check_cmd() - assert record[0].message.args[0] == "No commit found with range: 'master..master'" + assert "No commit found with range: 'master..master'" in str(excinfo) diff --git a/tests/commands/test_commit_command.py b/tests/commands/test_commit_command.py index 32da703616..5e0632d48f 100644 --- a/tests/commands/test_commit_command.py +++ b/tests/commands/test_commit_command.py @@ -44,9 +44,11 @@ def test_commit_retry_fails_no_backup(config, mocker): commit_mock = mocker.patch("commitizen.git.commit") commit_mock.return_value = cmd.Command("success", "", "", "") - with pytest.raises(NoCommitBackupError): + with pytest.raises(NoCommitBackupError) as excinfo: commands.Commit(config, {"retry": True})() + assert NoCommitBackupError.message in str(excinfo.value) + @pytest.mark.usefixtures("staging_is_clean") def test_commit_retry_works(config, mocker): @@ -107,10 +109,12 @@ def test_commit_when_nothing_to_commit(config, mocker): is_staging_clean_mock = mocker.patch("commitizen.git.is_staging_clean") is_staging_clean_mock.return_value = True - with pytest.raises(NothingToCommitError): + with pytest.raises(NothingToCommitError) as excinfo: commit_cmd = commands.Commit(config, {}) commit_cmd() + assert "No files added to staging!" in str(excinfo.value) + @pytest.mark.usefixtures("staging_is_clean") def test_commit_when_customized_expected_raised(config, mocker, capsys): @@ -119,10 +123,9 @@ def test_commit_when_customized_expected_raised(config, mocker, capsys): prompt_mock = mocker.patch("questionary.prompt") prompt_mock.side_effect = _err - with pytest.raises(CustomError): + with pytest.raises(CustomError) as excinfo: commit_cmd = commands.Commit(config, {}) commit_cmd() # Assert only the content in the formatted text - captured = capsys.readouterr() - assert "This is the root custom err" in captured.err + assert "This is the root custom err" in str(excinfo.value) diff --git a/tests/test_bump_update_version_in_files.py b/tests/test_bump_update_version_in_files.py index 1a89f8a89c..26a6ad677a 100644 --- a/tests/test_bump_update_version_in_files.py +++ b/tests/test_bump_update_version_in_files.py @@ -100,7 +100,14 @@ def test_file_version_inconsistent_error( ] old_version = "1.2.3" new_version = "2.0.0" - with pytest.raises(CurrentVersionNotFoundError): + with pytest.raises(CurrentVersionNotFoundError) as excinfo: bump.update_version_in_files( old_version, new_version, version_files, check_consistency=True ) + + expected_msg = ( + f"Current version 1.2.3 is not found in {inconsistent_python_version_file}.\n" + "The version defined in commitizen configuration and the ones in " + "version_files are possibly inconsistent." + ) + assert expected_msg in str(excinfo.value) diff --git a/tests/test_cli.py b/tests/test_cli.py index 37bc4bff8d..ad27c31464 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -17,14 +17,13 @@ def test_sysexit_no_argv(mocker, capsys): assert out.startswith("usage") -def test_cz_with_arg_but_without_command(mocker, capsys): +def test_cz_with_arg_but_without_command(mocker): testargs = ["cz", "--name", "cz_jira"] mocker.patch.object(sys, "argv", testargs) - with pytest.raises(NoCommandFoundError): + with pytest.raises(NoCommandFoundError) as excinfo: cli.main() - _, err = capsys.readouterr() - assert "Command is required" in err + assert "Command is required" in str(excinfo.value) def test_name(mocker, capsys): diff --git a/tests/test_conf.py b/tests/test_conf.py index b03475055a..ad3dd484b1 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -142,9 +142,11 @@ def test_find_git_project_root(tmpdir): def test_read_cfg_when_not_in_a_git_project(tmpdir): with tmpdir.as_cwd() as _: - with pytest.raises(NotAGitProjectError): + with pytest.raises(NotAGitProjectError) as excinfo: config.read_cfg() + assert NotAGitProjectError.message in str(excinfo.value) + class TestInilConfig: def test_read_setup_cfg_without_commitizen_config(self, tmpdir): diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py index 7d79e4cc61..dd280fe897 100644 --- a/tests/test_cz_customize.py +++ b/tests/test_cz_customize.py @@ -39,10 +39,12 @@ def config(): def test_initialize_cz_customize_failed(): - with pytest.raises(MissingConfigError): + with pytest.raises(MissingConfigError) as excinfo: config = BaseConfig() _ = CustomizeCommitsCz(config) + assert MissingConfigError.message in str(excinfo.value) + def test_bump_pattern(config): cz = CustomizeCommitsCz(config) diff --git a/tests/test_factory.py b/tests/test_factory.py index 5104f0e2ec..1a2eb7178d 100644 --- a/tests/test_factory.py +++ b/tests/test_factory.py @@ -15,5 +15,7 @@ def test_factory(): def test_factory_fails(): config = BaseConfig() config.settings.update({"name": "Nothing"}) - with pytest.raises(NoCommitizenFoundException): + with pytest.raises(NoCommitizenFoundException) as excinfo: factory.commiter_factory(config) + + assert "The committer has not been found in the system." in str(excinfo) From 799e373fe426f8c0ff1a4128f3d086ccda4407f9 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 14 Jun 2020 17:05:19 +0800 Subject: [PATCH 151/427] feat(cli): enable displaying all traceback for CommitizenException when --debug flag is used --- commitizen/cli.py | 15 +++++++-------- tests/test_cli.py | 10 ++-------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index 2b6f9648c1..bcba5cf86d 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -2,6 +2,7 @@ import logging import sys import warnings +from functools import partial from decli import cli @@ -241,15 +242,19 @@ original_excepthook = sys.excepthook -def commitizen_excepthook(type, value, tracekback): +def commitizen_excepthook(type, value, tracekback, debug=False): if isinstance(value, CommitizenException): if value.message: value.output_method(value.message) + if debug: + original_excepthook(type, value, tracekback) sys.exit(value.exit_code) else: original_excepthook(type, value, tracekback) +commitizen_debug_excepthook = partial(commitizen_excepthook, debug=True) + sys.excepthook = commitizen_excepthook @@ -284,14 +289,8 @@ def main(): args.func = commands.Version if args.debug: - warnings.warn( - ( - "Debug will be deprecated in next major version. " - "Please remove it from your scripts" - ), - category=DeprecationWarning, - ) logging.getLogger("commitizen").setLevel(logging.DEBUG) + sys.excepthook = commitizen_debug_excepthook # TODO: This try block can be removed after command is required in 2.0 # Handle the case that argument is given, but no command is provided diff --git a/tests/test_cli.py b/tests/test_cli.py index ad27c31464..7eb4192433 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -73,11 +73,5 @@ def test_arg_version(mocker, capsys): def test_arg_debug(mocker): testargs = ["cz", "--debug", "info"] mocker.patch.object(sys, "argv", testargs) - - with pytest.warns(DeprecationWarning) as record: - cli.main() - - assert record[0].message.args[0] == ( - "Debug will be deprecated in next major version. " - "Please remove it from your scripts" - ) + cli.main() + assert sys.excepthook.keywords.get("debug") is True From da79d1e194e472110c9c5753ed98512b3e622e71 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 14 Jun 2020 17:27:07 +0800 Subject: [PATCH 152/427] test(cz/customize): cover customized info from info_path --- tests/test_cz_customize.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py index dd280fe897..5cc3d546b2 100644 --- a/tests/test_cz_customize.py +++ b/tests/test_cz_customize.py @@ -117,3 +117,22 @@ def test_schema(config): def test_info(config): cz = CustomizeCommitsCz(config) assert "This is a customized cz." in cz.info() + + +def test_info_with_info_path(tmpdir): + with tmpdir.as_cwd(): + tmpfile = tmpdir.join("info.txt") + tmpfile.write("Test info") + + toml_str = """ + [tool.commitizen.customize] + message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" + example = "feature: this feature enable customize through config file" + schema = "<type>: <body>" + bump_pattern = "^(break|new|fix|hotfix)" + bump_map = {"break" = "MAJOR", "new" = "MINOR", "fix" = "PATCH", "hotfix" = "PATCH"} + info_path = "info.txt" + """ + config = TomlConfig(data=toml_str, path="not_exist.toml") + cz = CustomizeCommitsCz(config) + assert "Test info" in cz.info() From 182a58f212168d9187ae8cce842215e41fd48e41 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 14 Jun 2020 17:47:29 +0800 Subject: [PATCH 153/427] test(cli): add test cast for commitizen_excepthook --- tests/test_cli.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index 7eb4192433..a2fb7b8077 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -4,7 +4,7 @@ from commitizen import cli from commitizen.__version__ import __version__ -from commitizen.exceptions import ExpectedExit, NoCommandFoundError +from commitizen.exceptions import ExpectedExit, NoCommandFoundError, NotAGitProjectError def test_sysexit_no_argv(mocker, capsys): @@ -75,3 +75,22 @@ def test_arg_debug(mocker): mocker.patch.object(sys, "argv", testargs) cli.main() assert sys.excepthook.keywords.get("debug") is True + + +def test_commitizen_excepthook(capsys): + with pytest.raises(SystemExit) as excinfo: + cli.commitizen_excepthook(NotAGitProjectError, NotAGitProjectError(), "") + + assert excinfo.type == SystemExit + assert excinfo.value.code == NotAGitProjectError.exit_code + + +def test_commitizen_debug_excepthook(capsys): + with pytest.raises(SystemExit) as excinfo: + cli.commitizen_excepthook( + NotAGitProjectError, NotAGitProjectError(), "", debug=True, + ) + + assert excinfo.type == SystemExit + assert excinfo.value.code == NotAGitProjectError.exit_code + assert "NotAGitProjectError" in str(excinfo.traceback[0]) From c2893d1be552d721fd26c911e1cee28679b4ca1f Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 14 Jun 2020 17:58:03 +0800 Subject: [PATCH 154/427] test(commands/commit): add test case for raising non customized exception --- tests/commands/test_commit_command.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/commands/test_commit_command.py b/tests/commands/test_commit_command.py index 5e0632d48f..a4f3a59ef2 100644 --- a/tests/commands/test_commit_command.py +++ b/tests/commands/test_commit_command.py @@ -129,3 +129,14 @@ def test_commit_when_customized_expected_raised(config, mocker, capsys): # Assert only the content in the formatted text assert "This is the root custom err" in str(excinfo.value) + + +@pytest.mark.usefixtures("staging_is_clean") +def test_commit_when_non_customized_expected_raised(config, mocker, capsys): + _err = ValueError() + prompt_mock = mocker.patch("questionary.prompt") + prompt_mock.side_effect = _err + + with pytest.raises(ValueError): + commit_cmd = commands.Commit(config, {}) + commit_cmd() From 15e71764d243ea3bcfda72a50be4f77e86f34155 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 14 Jun 2020 18:05:23 +0800 Subject: [PATCH 155/427] test(config): add test case for load global conf --- tests/test_conf.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/test_conf.py b/tests/test_conf.py index ad3dd484b1..d78ed36d9b 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -103,6 +103,16 @@ def empty_pyproject_ok_cz(): os.remove(cz) +def test_load_global_conf(mocker, tmpdir): + with tmpdir.as_cwd(): + config_file = tmpdir.join(".cz") + config_file.write(RAW_CONFIG) + + mocked_path = mocker.patch("commitizen.config.Path", return_value=Path(".cz")) + mocked_path.home.return_value = Path(tmpdir) + print(config.load_global_conf()) + + @pytest.mark.parametrize( "config_files_manager", defaults.config_files.copy(), indirect=True ) From 4a1b89b7baf0e366dbe09f500bb1a693a1cd1399 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 14 Jun 2020 19:07:51 +0800 Subject: [PATCH 156/427] test: add multiple test cases --- tests/commands/test_commit_command.py | 11 +++++++++++ tests/test_cz_base.py | 6 ++++++ tests/test_cz_conventional_commits.py | 5 +++++ tests/test_cz_customize.py | 14 ++++++++++++++ 4 files changed, 36 insertions(+) diff --git a/tests/commands/test_commit_command.py b/tests/commands/test_commit_command.py index a4f3a59ef2..dd168bf31a 100644 --- a/tests/commands/test_commit_command.py +++ b/tests/commands/test_commit_command.py @@ -8,6 +8,7 @@ CommitError, CustomError, DryRunExit, + NoAnswersError, NoCommitBackupError, NothingToCommitError, ) @@ -140,3 +141,13 @@ def test_commit_when_non_customized_expected_raised(config, mocker, capsys): with pytest.raises(ValueError): commit_cmd = commands.Commit(config, {}) commit_cmd() + + +@pytest.mark.usefixtures("staging_is_clean") +def test_commit_when_no_user_answer(config, mocker, capsys): + prompt_mock = mocker.patch("questionary.prompt") + prompt_mock.return_value = None + + with pytest.raises(NoAnswersError): + commit_cmd = commands.Commit(config, {}) + commit_cmd() diff --git a/tests/test_cz_base.py b/tests/test_cz_base.py index b3b8fe4fb8..04cc7d9e83 100644 --- a/tests/test_cz_base.py +++ b/tests/test_cz_base.py @@ -51,3 +51,9 @@ def test_info(config): cz = DummyCz(config) with pytest.raises(NotImplementedError): cz.info() + + +def test_process_commit(config): + cz = DummyCz(config) + message = cz.process_commit("test(test_scope): this is test msg") + assert message == "test(test_scope): this is test msg" diff --git a/tests/test_cz_conventional_commits.py b/tests/test_cz_conventional_commits.py index 41ed9b0b7d..57ee37c6f5 100644 --- a/tests/test_cz_conventional_commits.py +++ b/tests/test_cz_conventional_commits.py @@ -112,3 +112,8 @@ def test_info(config): conventional_commits = ConventionalCommitsCz(config) info = conventional_commits.info() assert isinstance(info, str) + +def test_process_commit(config): + conventional_commits = ConventionalCommitsCz(config) + message = conventional_commits.process_commit("test(test_scope): this is test msg") + assert message == "this is test msg" diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py index 5cc3d546b2..9628bd208d 100644 --- a/tests/test_cz_customize.py +++ b/tests/test_cz_customize.py @@ -136,3 +136,17 @@ def test_info_with_info_path(tmpdir): config = TomlConfig(data=toml_str, path="not_exist.toml") cz = CustomizeCommitsCz(config) assert "Test info" in cz.info() + + +def test_info_without_info(): + toml_str = """ + [tool.commitizen.customize] + message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" + example = "feature: this feature enable customize through config file" + schema = "<type>: <body>" + bump_pattern = "^(break|new|fix|hotfix)" + bump_map = {"break" = "MAJOR", "new" = "MINOR", "fix" = "PATCH", "hotfix" = "PATCH"} + """ + config = TomlConfig(data=toml_str, path="not_exist.toml") + cz = CustomizeCommitsCz(config) + assert cz.info() is None From 3dd29a54c27a882c2bdcf60eefe3832967b75415 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 14 Jun 2020 19:14:10 +0800 Subject: [PATCH 157/427] style: reformat --- commitizen/commands/init.py | 2 +- tests/test_cz_conventional_commits.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/commitizen/commands/init.py b/commitizen/commands/init.py index 83a30f86a7..3cbb7e5423 100644 --- a/commitizen/commands/init.py +++ b/commitizen/commands/init.py @@ -2,10 +2,10 @@ from packaging.version import Version from commitizen import factory, out -from commitizen.exceptions import ExpectedExit, NoAnswersError from commitizen.config import BaseConfig, IniConfig, TomlConfig from commitizen.cz import registry from commitizen.defaults import long_term_support_config_files +from commitizen.exceptions import ExpectedExit, NoAnswersError from commitizen.git import get_latest_tag_name, get_tag_names diff --git a/tests/test_cz_conventional_commits.py b/tests/test_cz_conventional_commits.py index 57ee37c6f5..de6a3c30d4 100644 --- a/tests/test_cz_conventional_commits.py +++ b/tests/test_cz_conventional_commits.py @@ -113,6 +113,7 @@ def test_info(config): info = conventional_commits.info() assert isinstance(info, str) + def test_process_commit(config): conventional_commits = ConventionalCommitsCz(config) message = conventional_commits.process_commit("test(test_scope): this is test msg") From 7a8d3451767dafa346893302e075e8a2c0ecd8b5 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 14 Jun 2020 21:13:50 +0800 Subject: [PATCH 158/427] refactor(commands/init): add test case and remove unaccessible code --- commitizen/commands/init.py | 5 +---- tests/commands/test_init_command.py | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/commitizen/commands/init.py b/commitizen/commands/init.py index 3cbb7e5423..9310de254d 100644 --- a/commitizen/commands/init.py +++ b/commitizen/commands/init.py @@ -5,7 +5,7 @@ from commitizen.config import BaseConfig, IniConfig, TomlConfig from commitizen.cz import registry from commitizen.defaults import long_term_support_config_files -from commitizen.exceptions import ExpectedExit, NoAnswersError +from commitizen.exceptions import NoAnswersError from commitizen.git import get_latest_tag_name, get_tag_names @@ -102,8 +102,5 @@ def _ask_tag_format(self, latest_tag) -> str: return tag_format def _update_config_file(self, values): - if not values: - raise ExpectedExit("The configuration were all set. Nothing to add.") - for key, value in values.items(): self.config.set_key(key, value) diff --git a/tests/commands/test_init_command.py b/tests/commands/test_init_command.py index 1de8fef06a..39a0794005 100644 --- a/tests/commands/test_init_command.py +++ b/tests/commands/test_init_command.py @@ -1,4 +1,7 @@ +import pytest + from commitizen import commands +from commitizen.exceptions import NoAnswersError class FakeQuestion: @@ -43,3 +46,24 @@ def test_init_when_config_already_exists(config, capsys): commands.Init(config)() captured = capsys.readouterr() assert captured.out == f"Config file {path} already exists\n" + + +def test_init_without_choosing_tag(config, mocker, tmpdir): + mocker.patch( + "commitizen.commands.init.get_tag_names", return_value=["0.0.1", "0.0.2"] + ) + mocker.patch("commitizen.commands.init.get_latest_tag_name", return_value="0.0.2") + mocker.patch( + "questionary.select", + side_effect=[ + FakeQuestion("pyproject.toml"), + FakeQuestion("cz_conventional_commits"), + FakeQuestion(""), + ], + ) + mocker.patch("questionary.confirm", return_value=FakeQuestion(False)) + mocker.patch("questionary.text", return_value=FakeQuestion("y")) + + with tmpdir.as_cwd(): + with pytest.raises(NoAnswersError): + commands.Init(config)() From caf42cc865e20b860f218f95afa0893a14774135 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 14 Jun 2020 21:32:40 +0800 Subject: [PATCH 159/427] test(commands/changelog): add test case for running changelog without revision --- tests/commands/test_changelog_command.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index 0500ed0da0..cb731bb840 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -6,7 +6,7 @@ from commitizen import cli, git from commitizen.commands.changelog import Changelog -from commitizen.exceptions import DryRunExit, NoCommitsFoundError +from commitizen.exceptions import DryRunExit, NoCommitsFoundError, NoRevisionError from tests.utils import create_file_and_commit @@ -295,3 +295,21 @@ def test_changelog_multiple_incremental_do_not_add_new_lines( out = f.read() assert out.startswith("#") + + +def test_changelog_without_revision(mocker, tmp_commitizen_project): + changelog_file = tmp_commitizen_project.join("CHANGELOG.md") + changelog_file.write( + """ + # Unreleased + + ## v1.0.0 + """ + ) + + # create_file_and_commit("feat: new file") + testargs = ["cz", "changelog", "--incremental"] + mocker.patch.object(sys, "argv", testargs) + + with pytest.raises(NoRevisionError): + cli.main() From 5dfdeebc3051c533d6d838ff9a236a3a6c303129 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 14 Jun 2020 21:41:54 +0800 Subject: [PATCH 160/427] test(commands/changelog): add test case when tag name and the latest tag in changelog are different --- tests/commands/test_changelog_command.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index cb731bb840..630d1d6495 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -313,3 +313,25 @@ def test_changelog_without_revision(mocker, tmp_commitizen_project): with pytest.raises(NoRevisionError): cli.main() + + +def test_changelog_with_different_tag_name_and_changelog_content( + mocker, tmp_commitizen_project +): + changelog_file = tmp_commitizen_project.join("CHANGELOG.md") + changelog_file.write( + """ + # Unreleased + + ## v1.0.0 + """ + ) + create_file_and_commit("feat: new file") + git.tag("2.0.0") + + # create_file_and_commit("feat: new file") + testargs = ["cz", "changelog", "--incremental"] + mocker.patch.object(sys, "argv", testargs) + + with pytest.raises(NoRevisionError): + cli.main() From 31c570b4f09e200ab1e2c14634e92b3236e28b9c Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 14 Jun 2020 22:17:47 +0800 Subject: [PATCH 161/427] refactor(exception): Rename CommitFailedError and TagFailedError with Bump prefix these errors are only for `cz bump` --- commitizen/commands/bump.py | 8 ++++---- commitizen/exceptions.py | 12 ++++++------ tests/commands/test_bump_command.py | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 1d37a9e4c1..d892cc5a87 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -7,13 +7,13 @@ from commitizen.commands.changelog import Changelog from commitizen.config import BaseConfig from commitizen.exceptions import ( - CommitFailedError, + BumpCommitFailedError, + BumpTagFailedError, DryRunExit, ExpectedExit, NoCommitsFoundError, NoPatternMapError, NoVersionSpecifiedError, - TagFailedError, ) @@ -151,10 +151,10 @@ def __call__(self): # noqa: C901 self.config.set_key("version", new_version.public) c = git.commit(message, args=self._get_commit_args()) if c.err: - raise CommitFailedError(f'git.commit error: "{c.err.strip()}"') + raise BumpCommitFailedError(f'git.commit error: "{c.err.strip()}"') c = git.tag(new_tag_version) if c.err: - raise TagFailedError(c.err) + raise BumpTagFailedError(c.err) out.success("Done!") def _get_commit_args(self): diff --git a/commitizen/exceptions.py b/commitizen/exceptions.py index b1ea255f63..36887910ac 100644 --- a/commitizen/exceptions.py +++ b/commitizen/exceptions.py @@ -10,8 +10,8 @@ class ExitCode(enum.IntEnum): NO_COMMITS_FOUND = 3 NO_VERSION_SPECIFIED = 4 NO_PATTERN_MAP = 5 - COMMIT_FAILED = 6 - TAG_FAILED = 7 + BUMP_COMMIT_FAILED = 6 + BUMP_TAG_FAILED = 7 NO_ANSWERS = 8 COMMIT_ERROR = 9 NO_COMMIT_BACKUP = 10 @@ -84,12 +84,12 @@ class NoPatternMapError(CommitizenException): exit_code = ExitCode.NO_PATTERN_MAP -class CommitFailedError(CommitizenException): - exit_code = ExitCode.COMMIT_FAILED +class BumpCommitFailedError(CommitizenException): + exit_code = ExitCode.BUMP_COMMIT_FAILED -class TagFailedError(CommitizenException): - exit_code = ExitCode.TAG_FAILED +class BumpTagFailedError(CommitizenException): + exit_code = ExitCode.BUMP_TAG_FAILED class CurrentVersionNotFoundError(CommitizenException): diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index fd3089eed8..c2454f576b 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -4,7 +4,7 @@ from commitizen import cli, cmd, git from commitizen.exceptions import ( - CommitFailedError, + BumpCommitFailedError, CurrentVersionNotFoundError, DryRunExit, ExpectedExit, @@ -81,7 +81,7 @@ def test_bump_on_git_with_hooks_no_verify_disabled(mocker): testargs = ["cz", "bump", "--yes"] mocker.patch.object(sys, "argv", testargs) - with pytest.raises(CommitFailedError) as excinfo: + with pytest.raises(BumpCommitFailedError) as excinfo: cli.main() assert 'git.commit error: "0.1.0"' in str(excinfo.value) From a3af3a962e6b07bc76ae216d63f58866dab4a03c Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 14 Jun 2020 22:25:39 +0800 Subject: [PATCH 162/427] refactor(exception): rename MissingConfigError as MissingCzCustomizeConfigError --- commitizen/cz/customize/customize.py | 4 ++-- commitizen/exceptions.py | 6 +++--- tests/test_cz_customize.py | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/commitizen/cz/customize/customize.py b/commitizen/cz/customize/customize.py index 02ce3711e6..122dc9a4ee 100644 --- a/commitizen/cz/customize/customize.py +++ b/commitizen/cz/customize/customize.py @@ -8,7 +8,7 @@ from commitizen import defaults from commitizen.config import BaseConfig from commitizen.cz.base import BaseCommitizen -from commitizen.exceptions import MissingConfigError +from commitizen.exceptions import MissingCzCustomizeConfigError __all__ = ["CustomizeCommitsCz"] @@ -21,7 +21,7 @@ def __init__(self, config: BaseConfig): super(CustomizeCommitsCz, self).__init__(config) if "customize" not in self.config.settings: - raise MissingConfigError() + raise MissingCzCustomizeConfigError() self.custom_settings = self.config.settings["customize"] custom_bump_pattern = self.custom_settings.get("bump_pattern") diff --git a/commitizen/exceptions.py b/commitizen/exceptions.py index 36887910ac..8610a6fa74 100644 --- a/commitizen/exceptions.py +++ b/commitizen/exceptions.py @@ -19,7 +19,7 @@ class ExitCode(enum.IntEnum): CUSTOM_ERROR = 12 NO_COMMAND_FOUND = 13 INVALID_COMMIT_MSG = 14 - MISSING_CONFIG = 15 + MISSING_CZ_CUSTOMIZE_CONFIG = 15 NO_REVISION = 16 CURRENT_VERSION_NOT_FOUND = 17 INVALID_COMMAND_ARGUMENT = 18 @@ -62,8 +62,8 @@ class NotAGitProjectError(CommitizenException): message = "fatal: not a git repository (or any of the parent directories): .git" -class MissingConfigError(CommitizenException): - exit_code = ExitCode.MISSING_CONFIG +class MissingCzCustomizeConfigError(CommitizenException): + exit_code = ExitCode.MISSING_CZ_CUSTOMIZE_CONFIG message = "fatal: customize is not set in configuration file." diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py index 9628bd208d..11b14ab596 100644 --- a/tests/test_cz_customize.py +++ b/tests/test_cz_customize.py @@ -2,7 +2,7 @@ from commitizen.config import BaseConfig, TomlConfig from commitizen.cz.customize import CustomizeCommitsCz -from commitizen.exceptions import MissingConfigError +from commitizen.exceptions import MissingCzCustomizeConfigError @pytest.fixture(scope="module") @@ -39,11 +39,11 @@ def config(): def test_initialize_cz_customize_failed(): - with pytest.raises(MissingConfigError) as excinfo: + with pytest.raises(MissingCzCustomizeConfigError) as excinfo: config = BaseConfig() _ = CustomizeCommitsCz(config) - assert MissingConfigError.message in str(excinfo.value) + assert MissingCzCustomizeConfigError.message in str(excinfo.value) def test_bump_pattern(config): From 32287f0ed1937850fa9b3be25cbcf3a9d44a4698 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 14 Jun 2020 22:29:16 +0800 Subject: [PATCH 163/427] docs: exit codes --- docs/exit_codes.md | 28 ++++++++++++++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 29 insertions(+) create mode 100644 docs/exit_codes.md diff --git a/docs/exit_codes.md b/docs/exit_codes.md new file mode 100644 index 0000000000..d83c93d991 --- /dev/null +++ b/docs/exit_codes.md @@ -0,0 +1,28 @@ +# Exit Codes + +Commitizen handles expected exceptions through `CommitizenException` and returns different exit codes for different situations. They could be useful if you want to ignore specific errors in your pipeline. + +These exit codes can be found in `commitizen/exceptions.py::ExitCode`. + +| Exception | Exit Code | Description | +| --------- | --------- | ----------- | +| ExpectedExit | 0 | Expected exit | +| DryRunExit | 0 | Exit due to passing `--dry-run` option | +| NoCommitizenFoundException | 1 | Using a cz (e.g., `cz_jira`) that cannot be found in your system | +| NotAGitProjectError | 2 | Not in a git project | +| NoCommitsFoundError | 4 | No commit found | +| NoVersionSpecifiedError | 4 | Version can not be found in configuration file | +| NoPatternMapError | 5 | bump / changelog pattern or map can not be found in configuration file | +| BumpCommitFailedError | 6 | Commit error when bumping version | +| BumpTagFailedError | 7 | Tag error when bumping version | +| NoAnswersError | 8 | No user response given | +| CommitError | 9 | git commit error | +| NoCommitBackupError | 10 | Commit back up file cannot be found | +| NothingToCommitError | 11 | Nothing in staging to be committed | +| CustomError | 12 | `CzException` raised | +| NoCommandFoundError | 13 | No command found when running commitizen cli (e.g., `cz --debug`) | +| InvalidCommitMessageError | 14 | The commit message does not pass `cz check` | +| MissingConfigError | 15 | Configuration missed for `cz_customize` | +| NoRevisionError | 16 | No revision found | +| CurrentVersionNotFoundError | 17 | current version cannot be found in *version_files* | +| InvalidCommandArgumentError | 18 | The argument provide to command is invalid (e.g. `cz check -commit-msg-file filename --rev-range master..`) | diff --git a/mkdocs.yml b/mkdocs.yml index 52ef5415ad..51952471b2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -21,6 +21,7 @@ nav: - Writing commits: 'tutorials/writing_commits.md' - GitLab CI: 'tutorials/gitlab_ci.md' - Github Actions: 'tutorials/github_actions.md' + - Exit Codes: 'exit_codes.md' - Third-Party Commitizen Templates: 'third-party-commitizen.md' - Contributing: 'contributing.md' From cbb9ad756366f8cee410854a675f0345b00a312c Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sun, 14 Jun 2020 15:24:36 +0000 Subject: [PATCH 164/427] =?UTF-8?q?bump:=20version=201.22.3=20=E2=86=92=20?= =?UTF-8?q?1.23.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 18 ++++++++++++++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b360ee97dc..a13e79ea11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +## v1.23.0 (2020-06-14) + +### Refactor + +- **exception**: rename MissingConfigError as MissingCzCustomizeConfigError +- **exception**: Rename CommitFailedError and TagFailedError with Bump prefix +- **commands/init**: add test case and remove unaccessible code +- **exception**: move output message related to exception into exception +- **exception**: implement message handling mechanism for CommitizenException +- **cli**: do not show traceback if the raised exception is CommitizenException +- introduce DryRunExit, ExpectedExit, NoCommandFoundError, InvalidCommandArgumentError +- use custom exception for error handling +- **error_codes**: remove unused NO_COMMIT_MSG error code + +### Feat + +- **cli**: enable displaying all traceback for CommitizenException when --debug flag is used + ## v1.22.3 (2020-06-10) ## v1.22.2 (2020-05-29) diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 90495751d4..282cfcb4e7 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.22.3" +__version__ = "1.23.0" diff --git a/pyproject.toml b/pyproject.toml index f39a6a56d4..8b897d24e6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.22.3" +version = "1.23.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.22.3" +version = "1.23.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 14f5de85a26c539d17566c180e0682ade9b5915e Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Wed, 24 Jun 2020 17:58:34 +0800 Subject: [PATCH 165/427] docs(customization): update title level --- docs/customization.md | 141 +++++++++++++++++++++--------------------- 1 file changed, 71 insertions(+), 70 deletions(-) diff --git a/docs/customization.md b/docs/customization.md index 8211e9120a..20f9ffb9fe 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -1,6 +1,75 @@ Customizing commitizen is not hard at all. +We have two different ways to do so. -## Customize through customizing a class +## 1. Customize in configuration file + +**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 bumping 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}}:{% if show_message %} {{message}}{% endif %}" +example = "feature: this feature enable customize through config file" +schema = "<type>: <body>" +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 = [{value = "feature", name = "feature: A new feature."}, {value = "bug fix", name = "bug fix: A bug fix."}] +# choices = ["feature", "fix"] # short version +message = "Select the type of change you are committing" + +[[tool.commitizen.customize.questions]] +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 + +| Parameter | Type | Default | Description | +| ------------------ | ------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `questions` | `dict` | `None` | Questions regarding the commit message. Detailed below. | +| `message_template` | `str` | `None` | The template for generating message from the given answers. `message_template` should either follow 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. | +| `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 `questions` content + +| Parameter | Type | Default | Description | +| --------- | ------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `type` | `str` | `None` | The type of questions. Valid type: `list`, `input` and etc. [See More](https://github.com/tmbo/questionary#different-question-types) | +| `name` | `str` | `None` | The key for the value answered by user. It's used in `message_template` | +| `message` | `str` | `None` | Detail description for the question. | +| `choices` | `list` | `None` | (OPTIONAL) The choices when `type = list`. Either use a list of values or a list of dicitionaries with `name` and `value` keys. See examples above. | +| `default` | `Any` | `None` | (OPTIONAL) The default value for this question. | +| `filter` | `str` | `None` | (Optional) Validator for user's answer. **(Work in Progress)** | + +## 2. Customize through customizing a class The basic steps are: @@ -132,7 +201,7 @@ cz -n cz_strange bump [convcomms]: https://github.com/commitizen-tools/commitizen/blob/master/commitizen/cz/conventional_commits/conventional_commits.py -## Custom changelog generator +### Custom changelog generator The changelog generator should just work in a very basic manner without touching anything. You can customize it of course, and this are the variables you need to add to your custom `BaseCommitizen`. @@ -196,71 +265,3 @@ 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 bumping 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}}:{% if show_message %} {{message}}{% endif %}" -example = "feature: this feature enable customize through config file" -schema = "<type>: <body>" -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 = [{value = "feature", name = "feature: A new feature."}, {value = "bug fix", name = "bug fix: A bug fix."}] -# choices = ["feature", "fix"] # short version -message = "Select the type of change you are committing" - -[[tool.commitizen.customize.questions]] -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 - -| Parameter | Type | Default | Description | -| ------------------ | ------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `questions` | `dict` | `None` | Questions regarding the commit message. Detailed below. | -| `message_template` | `str` | `None` | The template for generating message from the given answers. `message_template` should either follow 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. | -| `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 `questions` content - -| Parameter | Type | Default | Description | -| --------- | ------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `type` | `str` | `None` | The type of questions. Valid type: `list`, `input` and etc. [See More](https://github.com/tmbo/questionary#different-question-types) | -| `name` | `str` | `None` | The key for the value answered by user. It's used in `message_template` | -| `message` | `str` | `None` | Detail description for the question. | -| `choices` | `list` | `None` | (OPTIONAL) The choices when `type = list`. Either use a list of values or a list of dicitionaries with `name` and `value` keys. See examples above. | -| `default` | `Any` | `None` | (OPTIONAL) The default value for this question. | -| `filter` | `str` | `None` | (Optional) Validator for user's answer. **(Work in Progress)** | From f5e11338e64096ec8252e86d96f7f9d373c4460a Mon Sep 17 00:00:00 2001 From: Alexandre Gerona <alecgerona@gmail.com> Date: Sat, 27 Jun 2020 22:52:24 +0800 Subject: [PATCH 166/427] build(.gitignore): Add .idea to .gitignore To cater to Jetbrains IDE users. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5cec5fb4a0..5b4e933e35 100644 --- a/.gitignore +++ b/.gitignore @@ -104,6 +104,7 @@ venv.bak/ # mypy .mypy_cache/ +.idea .vscode/ *.bak From 48c97b5d41a3c0b9166ec0d8943c10c9cd642bd6 Mon Sep 17 00:00:00 2001 From: Alexandre Gerona <alecgerona@gmail.com> Date: Sat, 27 Jun 2020 22:54:57 +0800 Subject: [PATCH 167/427] docs(contributing.md): Correct typos and sentences --- docs/contributing.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/contributing.md b/docs/contributing.md index 14788790cb..dfbf2a9c7f 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -8,13 +8,13 @@ If you're a first-time contributor, you can check the issues with [good first is ## Before making a pull request -1. Fork [the repository](https://github.com/commitizen-tools/commitizen) -2. Clone the repository from you GitHub -3. Setup development environment through [poetry](https://python-poetry.org/) (`poetry install`) -4. Check out a new branch and add your modification -5. Add test cases for all your changes +1. Fork [the repository](https://github.com/commitizen-tools/commitizen). +2. Clone the repository from your GitHub. +3. Setup development environment through [poetry](https://python-poetry.org/) (`poetry install`). +4. Check out a new branch and add your modification. +5. Add test cases for all your changes. (We use [CodeCov](https://codecov.io/) to ensure our test coverage does not drop.) -6. Use [commitizen](https://github.com/commitizen-tools/commitizen) to do git commit -7. Run `./scripts/lint` and `./scripts/test` to ensure you follow the coding style and the tests pass -8. Update `READMD.md` and `CHANGELOG.md` for your changes +6. Use [commitizen](https://github.com/commitizen-tools/commitizen) to do git commit. +7. Run `./scripts/lint` and `./scripts/test` to ensure you follow the coding style and the tests pass. +8. Update `READMD.md` and `CHANGELOG.md` for your changes. 9. Send a [pull request](https://github.com/commitizen-tools/commitizen/pulls) 🙏 From 6ec81699e91e19c3924395e50bc92e5074522de8 Mon Sep 17 00:00:00 2001 From: Alexandre Gerona <alecgerona@gmail.com> Date: Sat, 27 Jun 2020 22:55:46 +0800 Subject: [PATCH 168/427] docs(README.md): Add pre-commit integration information in README.md --- docs/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/README.md b/docs/README.md index a7d4333b1d..e5fe2ae2c5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -74,6 +74,20 @@ or the shortcut cz c ``` +### Integrating with Pre-commit +Commitizen can lint your commit message for you with `cz check`. +You can integrate this in your [pre-commit](https://pre-commit.com/) config with: +```yaml +--- +repos: + - repo: https://github.com/commitizen-tools/commitizen + rev: v1.17.0 + hooks: + - id: commitizen + stages: [commit-msg] +``` +Read more about the `check` command [here](https://commitizen-tools.github.io/commitizen/check/). + ### Help ```bash From bd01c8dc2694b69696884b5a9295c332f768e13b Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 28 Jun 2020 13:20:09 +0800 Subject: [PATCH 169/427] docs(external_links): add talks, articles section to external_links --- docs/external_links.md | 9 +++++++++ mkdocs.yml | 1 + 2 files changed, 10 insertions(+) create mode 100644 docs/external_links.md diff --git a/docs/external_links.md b/docs/external_links.md new file mode 100644 index 0000000000..97d56442bb --- /dev/null +++ b/docs/external_links.md @@ -0,0 +1,9 @@ +## Talks +* commitizen-tools: What can we gain from crafting a git message convention + * Speaker: Wei Lee + * Occasion: Taipey.py 2020 June Meetup, Remote Python Pizza 2020 + * Material + * [slides](https://speakerdeck.com/leew/commitizen-tools-what-can-we-gain-from-crafting-a-git-message-convention-at-taipey-dot-py) + +## Articles +* [Python Table Manners - Commitizen: 規格化 commit message](https://lee-w.github.io/posts/tech/2020/03/python-table-manners-commitizen/) (Written in Traditional Mandarin) diff --git a/mkdocs.yml b/mkdocs.yml index 51952471b2..39c53d9500 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -24,6 +24,7 @@ nav: - Exit Codes: 'exit_codes.md' - Third-Party Commitizen Templates: 'third-party-commitizen.md' - Contributing: 'contributing.md' + - External Links: 'external_links.md' markdown_extensions: - markdown.extensions.codehilite: From 2f76fe9a87e2b54d88fca78ad3a6bc1d57c6f7c5 Mon Sep 17 00:00:00 2001 From: Alexandre Gerona <alecgerona@gmail.com> Date: Tue, 30 Jun 2020 13:23:16 +0800 Subject: [PATCH 170/427] docs(README): Change commitizen rev recommendation for pre-commit integration --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index e5fe2ae2c5..348bb62e43 100644 --- a/docs/README.md +++ b/docs/README.md @@ -81,7 +81,7 @@ You can integrate this in your [pre-commit](https://pre-commit.com/) config with --- repos: - repo: https://github.com/commitizen-tools/commitizen - rev: v1.17.0 + rev: master hooks: - id: commitizen stages: [commit-msg] From 38b7861708ec1f108770643af7615175b8b061ed Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Wed, 1 Jul 2020 10:16:57 +0800 Subject: [PATCH 171/427] ci: rename lint as reformat --- .github/pull_request_template.md | 2 +- docs/contributing.md | 2 +- scripts/{lint => reformat} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename scripts/{lint => reformat} (100%) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 82d423a897..579cb681b7 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -15,7 +15,7 @@ Please put an `x` in the box that applies ## Checklist: - [ ] Add test cases to all the changes you introduce -- [ ] Run `./script/lint` and `./script/test` locally to ensure this change passes linter check and test +- [ ] Run `./script/reformat` and `./script/test` locally to ensure this change passes linter check and test - [ ] Test the changes on the local machine manually - [ ] Update the documentation for the changes diff --git a/docs/contributing.md b/docs/contributing.md index dfbf2a9c7f..f835b5f713 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -15,6 +15,6 @@ If you're a first-time contributor, you can check the issues with [good first is 5. Add test cases for all your changes. (We use [CodeCov](https://codecov.io/) to ensure our test coverage does not drop.) 6. Use [commitizen](https://github.com/commitizen-tools/commitizen) to do git commit. -7. Run `./scripts/lint` and `./scripts/test` to ensure you follow the coding style and the tests pass. +7. Run `./scripts/reformat` and `./scripts/test` to ensure you follow the coding style and the tests pass. 8. Update `READMD.md` and `CHANGELOG.md` for your changes. 9. Send a [pull request](https://github.com/commitizen-tools/commitizen/pulls) 🙏 diff --git a/scripts/lint b/scripts/reformat similarity index 100% rename from scripts/lint rename to scripts/reformat From 774c3f850186bff49edbaf25cb885430037195c1 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Wed, 1 Jul 2020 10:17:13 +0800 Subject: [PATCH 172/427] ci(pre-commit): add pre-commit-config --- .pre-commit-config.yaml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..89803b65e2 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,26 @@ +default_stages: [push] +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.1.0 + hooks: + - id: check-vcs-permalinks + - id: end-of-file-fixer + - id: trailing-whitespace + args: [--markdown-linebreak-ext=md] + - id: debug-statements + - id: no-commit-to-branch + - repo: local + hooks: + - id: reformat + name: reformat + language: system + pass_filenames: false + entry: ./scripts/reformat + types: [python] + + - id: linter and test + name: linter and test + language: system + pass_filenames: false + entry: ./scripts/test + types: [python] From 7029c08476576b80ab277de49db238a5f5c3aefe Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Wed, 1 Jul 2020 10:17:34 +0800 Subject: [PATCH 173/427] style: fix eof and trailing spaces --- .codacy.yaml | 2 +- .github/workflows/pythonpublish.yaml | 1 - LICENSE | 2 +- .../cz/conventional_commits/conventional_commits_info.txt | 2 +- docs/README.md | 2 ++ pyproject.toml | 1 - 6 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.codacy.yaml b/.codacy.yaml index 3a31bdb7be..cab97400c0 100644 --- a/.codacy.yaml +++ b/.codacy.yaml @@ -1,3 +1,3 @@ exclude_paths: - 'tests/**' - - 'docs/**' \ No newline at end of file + - 'docs/**' diff --git a/.github/workflows/pythonpublish.yaml b/.github/workflows/pythonpublish.yaml index 937d6aa387..2a827518cc 100644 --- a/.github/workflows/pythonpublish.yaml +++ b/.github/workflows/pythonpublish.yaml @@ -28,4 +28,3 @@ jobs: PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | ./scripts/publish - diff --git a/LICENSE b/LICENSE index 881035d1d0..05cf267ae5 100644 --- a/LICENSE +++ b/LICENSE @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. diff --git a/commitizen/cz/conventional_commits/conventional_commits_info.txt b/commitizen/cz/conventional_commits/conventional_commits_info.txt index f1b5633e07..a076e4f5ec 100644 --- a/commitizen/cz/conventional_commits/conventional_commits_info.txt +++ b/commitizen/cz/conventional_commits/conventional_commits_info.txt @@ -28,4 +28,4 @@ information and is contained within parenthesis, e.g., feat(parser): add ability [optional body] -[optional footer] \ No newline at end of file +[optional footer] diff --git a/docs/README.md b/docs/README.md index 348bb62e43..718f663580 100644 --- a/docs/README.md +++ b/docs/README.md @@ -77,6 +77,7 @@ cz c ### Integrating with Pre-commit Commitizen can lint your commit message for you with `cz check`. You can integrate this in your [pre-commit](https://pre-commit.com/) config with: + ```yaml --- repos: @@ -86,6 +87,7 @@ repos: - id: commitizen stages: [commit-msg] ``` + Read more about the `check` command [here](https://commitizen-tools.github.io/commitizen/check/). ### Help diff --git a/pyproject.toml b/pyproject.toml index 8b897d24e6..2acc6c6d83 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -109,4 +109,3 @@ line_length = 88 [build-system] requires = ["poetry>=0.12"] build-backend = "poetry.masonry.api" - From 89df39e97d737338d9b39b283acb9de00a3cdb87 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Wed, 1 Jul 2020 10:23:35 +0800 Subject: [PATCH 174/427] docs(contributing): add pre-commit setup --- docs/contributing.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/contributing.md b/docs/contributing.md index f835b5f713..7973530a92 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -11,10 +11,11 @@ If you're a first-time contributor, you can check the issues with [good first is 1. Fork [the repository](https://github.com/commitizen-tools/commitizen). 2. Clone the repository from your GitHub. 3. Setup development environment through [poetry](https://python-poetry.org/) (`poetry install`). -4. Check out a new branch and add your modification. -5. Add test cases for all your changes. +4. Setup [pre-commit](https://pre-commit.com/) hook (`pre-commit install -t pre-commit -t pre-push`) +5. Check out a new branch and add your modification. +6. Add test cases for all your changes. (We use [CodeCov](https://codecov.io/) to ensure our test coverage does not drop.) -6. Use [commitizen](https://github.com/commitizen-tools/commitizen) to do git commit. -7. Run `./scripts/reformat` and `./scripts/test` to ensure you follow the coding style and the tests pass. -8. Update `READMD.md` and `CHANGELOG.md` for your changes. -9. Send a [pull request](https://github.com/commitizen-tools/commitizen/pulls) 🙏 +7. Use [commitizen](https://github.com/commitizen-tools/commitizen) to do git commit. +8. Run `./scripts/reformat` and `./scripts/test` to ensure you follow the coding style and the tests pass. +9. Update `READMD.md` and `CHANGELOG.md` for your changes. +10. Send a [pull request](https://github.com/commitizen-tools/commitizen/pulls) 🙏 From 4fddcbea44f931864b070b6f1915a175246c2eee Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Wed, 1 Jul 2020 10:30:23 +0800 Subject: [PATCH 175/427] ci(pre-commit): add commitizen to pre-commit config --- .pre-commit-config.yaml | 7 +++++++ docs/contributing.md | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 89803b65e2..c7c755faa9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,6 +9,13 @@ repos: args: [--markdown-linebreak-ext=md] - id: debug-statements - id: no-commit-to-branch + + - repo: https://github.com/Woile/commitizen + rev: v1.23.0 + hooks: + - id: commitizen + stages: [commit-msg] + - repo: local hooks: - id: reformat diff --git a/docs/contributing.md b/docs/contributing.md index 7973530a92..6966229ff1 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -11,7 +11,7 @@ If you're a first-time contributor, you can check the issues with [good first is 1. Fork [the repository](https://github.com/commitizen-tools/commitizen). 2. Clone the repository from your GitHub. 3. Setup development environment through [poetry](https://python-poetry.org/) (`poetry install`). -4. Setup [pre-commit](https://pre-commit.com/) hook (`pre-commit install -t pre-commit -t pre-push`) +4. Setup [pre-commit](https://pre-commit.com/) hook (`pre-commit install -t pre-commit -t pre-push -t commit-msg`) 5. Check out a new branch and add your modification. 6. Add test cases for all your changes. (We use [CodeCov](https://codecov.io/) to ensure our test coverage does not drop.) From e4ff8d036b3ce472549e95a09476e8dc6cec4b44 Mon Sep 17 00:00:00 2001 From: Marcelo <mmaia.cc@gmail.com> Date: Thu, 2 Jul 2020 18:33:02 -0300 Subject: [PATCH 176/427] docs(3rd-party): new template --- docs/third-party-commitizen.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/third-party-commitizen.md b/docs/third-party-commitizen.md index 0b09f015cf..d109746d2d 100644 --- a/docs/third-party-commitizen.md +++ b/docs/third-party-commitizen.md @@ -10,3 +10,11 @@ JIRA issue format, i.e. `project-issueNumber`. This standardises scopes in a meaningful way. It can be installed with `pip install conventional-JIRA`. + +### [Commitizen emoji](https://pypi.org/project/commitizen-emoji/) + +Just like *conventional commit* format, but with emojis and optionally time spent and related tasks. + +It can be installed with `pip install commitizen-emoji`. + +Usage: `cz --name cz_commitizen_emoji commit`. From a3019c898d1f961a83ccefe356af9b3cdc59c705 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 4 Jul 2020 19:04:34 +0800 Subject: [PATCH 177/427] docs(README): add "pre-commit install --hook-type commit-msg" command to pre-commit section --- docs/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/README.md b/docs/README.md index 718f663580..393ea5bc5e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -88,6 +88,12 @@ repos: stages: [commit-msg] ``` +After the configuration is added, you'll need to run + +```sh +pre-commit install --hook-type commit-msg +``` + Read more about the `check` command [here](https://commitizen-tools.github.io/commitizen/check/). ### Help From 332241bea47a0b7c10f6b33d925a4bd67f798aa1 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 4 Jul 2020 19:06:56 +0800 Subject: [PATCH 178/427] ci: rename scripts/reformat as scripts/format --- .github/pull_request_template.md | 2 +- .pre-commit-config.yaml | 6 +++--- docs/contributing.md | 2 +- scripts/{reformat => format} | 0 4 files changed, 5 insertions(+), 5 deletions(-) rename scripts/{reformat => format} (100%) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 579cb681b7..ed2a601064 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -15,7 +15,7 @@ Please put an `x` in the box that applies ## Checklist: - [ ] Add test cases to all the changes you introduce -- [ ] Run `./script/reformat` and `./script/test` locally to ensure this change passes linter check and test +- [ ] Run `./script/format` and `./script/test` locally to ensure this change passes linter check and test - [ ] Test the changes on the local machine manually - [ ] Update the documentation for the changes diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c7c755faa9..36bbcfb646 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,11 +18,11 @@ repos: - repo: local hooks: - - id: reformat - name: reformat + - id: format + name: format language: system pass_filenames: false - entry: ./scripts/reformat + entry: ./scripts/format types: [python] - id: linter and test diff --git a/docs/contributing.md b/docs/contributing.md index 6966229ff1..224aeb6442 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -16,6 +16,6 @@ If you're a first-time contributor, you can check the issues with [good first is 6. Add test cases for all your changes. (We use [CodeCov](https://codecov.io/) to ensure our test coverage does not drop.) 7. Use [commitizen](https://github.com/commitizen-tools/commitizen) to do git commit. -8. Run `./scripts/reformat` and `./scripts/test` to ensure you follow the coding style and the tests pass. +8. Run `./scripts/format` and `./scripts/test` to ensure you follow the coding style and the tests pass. 9. Update `READMD.md` and `CHANGELOG.md` for your changes. 10. Send a [pull request](https://github.com/commitizen-tools/commitizen/pulls) 🙏 diff --git a/scripts/reformat b/scripts/format similarity index 100% rename from scripts/reformat rename to scripts/format From 97c1b1cf79ec2882361be777520ae2a1a0a5d229 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 12 Jul 2020 17:18:17 +0800 Subject: [PATCH 179/427] build(poetry): add pre-commit to dev deps --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2acc6c6d83..53fe211777 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,7 @@ classifiers = [ ] [tool.poetry.dependencies] -python = "^3.6" +python = "^3.6.1" questionary = "^1.4.0" decli = "^0.5.0" colorama = "^0.4.1" @@ -67,6 +67,7 @@ mkdocs-material = "^4.1" isort = "^4.3.21" freezegun = "^0.3.15" pydocstyle = "^5.0.2" +pre-commit = "^2.6.0" [tool.poetry.scripts] cz = "commitizen.cli:main" From 21339923684bce9749830b50e5550f615b6908e5 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Mon, 13 Jul 2020 17:18:53 +0800 Subject: [PATCH 180/427] ci(github-action): rename job --- .github/workflows/bumpversion.yml | 2 +- .github/workflows/docspublish.yaml | 2 +- .github/workflows/pythonpackage.yml | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/bumpversion.yml b/.github/workflows/bumpversion.yml index dfaaa216e7..0ab565c0e0 100644 --- a/.github/workflows/bumpversion.yml +++ b/.github/workflows/bumpversion.yml @@ -6,7 +6,7 @@ on: - master jobs: - build: + bump-version: if: "!startsWith(github.event.head_commit.message, 'bump:')" runs-on: ubuntu-latest strategy: diff --git a/.github/workflows/docspublish.yaml b/.github/workflows/docspublish.yaml index d671c73c26..4cb3b47c32 100644 --- a/.github/workflows/docspublish.yaml +++ b/.github/workflows/docspublish.yaml @@ -6,7 +6,7 @@ on: - master jobs: - deploy: + publish-documentation: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 957754c32e..98c00105d8 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -3,8 +3,7 @@ name: Python package on: [pull_request] jobs: - build: - + python-check: runs-on: ubuntu-latest strategy: max-parallel: 4 From a37ed5caed8e0d4f01a7f17b002002d69b93331b Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Mon, 13 Jul 2020 17:31:50 +0800 Subject: [PATCH 181/427] ci(github-action): update pip when initialize environement --- .github/workflows/bumpversion.yml | 2 +- .github/workflows/pythonpackage.yml | 12 ++---------- .github/workflows/pythonpublish.yaml | 2 +- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/.github/workflows/bumpversion.yml b/.github/workflows/bumpversion.yml index 0ab565c0e0..cd4698de67 100644 --- a/.github/workflows/bumpversion.yml +++ b/.github/workflows/bumpversion.yml @@ -24,7 +24,7 @@ jobs: - name: Install dependencies run: | python --version - python -m pip install -U poetry + python -m pip install -U pip poetry - name: Configure repo run: | git config --local user.email "action@github.com" diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 98c00105d8..3fa8855279 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -20,22 +20,14 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python -m pip install --pre -U poetry + python -m pip install -U pip poetry poetry --version poetry install - - name: Run tests + - name: Run tests and linters run: | git config --global user.email "action@github.com" git config --global user.name "GitHub Action" ./scripts/test - - name: Check commit - run: | - poetry run python -m commitizen check --rev-range ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} || \ - if [ $$? == 3 ] ; then - exit 0; - else - exit 1; - fi - name: Upload coverage to Codecov if: runner.os == 'Linux' uses: codecov/codecov-action@v1.0.3 diff --git a/.github/workflows/pythonpublish.yaml b/.github/workflows/pythonpublish.yaml index 2a827518cc..e060663ba7 100644 --- a/.github/workflows/pythonpublish.yaml +++ b/.github/workflows/pythonpublish.yaml @@ -19,7 +19,7 @@ jobs: python-version: '3.x' - name: Install dependencies run: | - python -m pip install --pre -U poetry mkdocs mkdocs-material + python -m pip install -U pip poetry mkdocs mkdocs-material poetry --version poetry install - name: Publish From 2fdce2f7cc8c7894eb55bc6133952eb758cd4953 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Tue, 14 Jul 2020 16:43:36 +0800 Subject: [PATCH 182/427] fix: Raise NotAGitProjectError only in git related command Only Running `cz commit`, `cz bump` and `cz changelog` in a non git project will raise NotAGitProjectError Other commands like `cz --help` will work now #206 --- commitizen/commands/bump.py | 4 ++++ commitizen/commands/changelog.py | 4 ++++ commitizen/commands/commit.py | 4 ++++ commitizen/config/__init__.py | 8 ++++---- commitizen/git.py | 7 +++++++ tests/commands/test_bump_command.py | 11 +++++++++++ tests/commands/test_changelog_command.py | 16 +++++++++++++++- tests/commands/test_commit_command.py | 7 +++++++ tests/test_conf.py | 9 --------- 9 files changed, 56 insertions(+), 14 deletions(-) diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index d892cc5a87..d656a1b57a 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -13,6 +13,7 @@ ExpectedExit, NoCommitsFoundError, NoPatternMapError, + NotAGitProjectError, NoVersionSpecifiedError, ) @@ -21,6 +22,9 @@ class Bump: """Show prompt for the user to create a guided commit.""" def __init__(self, config: BaseConfig, arguments: dict): + if not git.is_git_project(): + raise NotAGitProjectError() + self.config: BaseConfig = config self.arguments: dict = arguments self.bump_settings: dict = { diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index bfe6776dde..e177062b58 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -10,6 +10,7 @@ NoCommitsFoundError, NoPatternMapError, NoRevisionError, + NotAGitProjectError, ) from commitizen.git import GitTag @@ -22,6 +23,9 @@ class Changelog: """Generate a changelog based on the commit history.""" def __init__(self, config: BaseConfig, args): + if not git.is_git_project(): + raise NotAGitProjectError() + self.config: BaseConfig = config self.cz = factory.commiter_factory(self.config) diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index 9f1d7ed57e..33b607ae45 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -13,6 +13,7 @@ DryRunExit, NoAnswersError, NoCommitBackupError, + NotAGitProjectError, NothingToCommitError, ) @@ -21,6 +22,9 @@ class Commit: """Show prompt for the user to create a guided commit.""" def __init__(self, config: BaseConfig, arguments: dict): + if not git.is_git_project(): + raise NotAGitProjectError() + self.config: BaseConfig = config self.cz = factory.commiter_factory(self.config) self.arguments = arguments diff --git a/commitizen/config/__init__.py b/commitizen/config/__init__.py index 4219306011..04c39f3dd4 100644 --- a/commitizen/config/__init__.py +++ b/commitizen/config/__init__.py @@ -3,7 +3,6 @@ from typing import Optional, Union from commitizen import defaults, git -from commitizen.exceptions import NotAGitProjectError from .base_config import BaseConfig from .ini_config import IniConfig @@ -37,12 +36,13 @@ def read_cfg() -> BaseConfig: conf = BaseConfig() git_project_root = git.find_git_project_root() - if not git_project_root: - raise NotAGitProjectError() + cfg_search_paths = [Path(".")] + if git_project_root: + cfg_search_paths.append(git_project_root) cfg_paths = ( path / Path(filename) - for path in [Path("."), git_project_root] + for path in cfg_search_paths for filename in defaults.config_files ) for filename in cfg_paths: diff --git a/commitizen/git.py b/commitizen/git.py index 3db37111be..ac33181ce6 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -135,3 +135,10 @@ def is_staging_clean() -> bool: c = cmd.run("git diff --no-ext-diff --name-only") c_cached = cmd.run("git diff --no-ext-diff --cached --name-only") return not (bool(c.out) or bool(c_cached.out)) + + +def is_git_project() -> bool: + c = cmd.run("git rev-parse --is-inside-work-tree") + if c.out.strip() == "true": + return True + return False diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index c2454f576b..511415c97c 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -10,6 +10,7 @@ ExpectedExit, NoCommitsFoundError, NoPatternMapError, + NotAGitProjectError, NoVersionSpecifiedError, ) from tests.utils import create_file_and_commit @@ -206,3 +207,13 @@ def test_bump_dry_run(mocker, capsys, tmp_commitizen_project): tag_exists = git.tag_exist("0.2.0") assert tag_exists is False + + +def test_bump_in_non_git_project(tmpdir, config, mocker): + testargs = ["cz", "bump", "--yes"] + mocker.patch.object(sys, "argv", testargs) + + with tmpdir.as_cwd(): + with pytest.raises(NotAGitProjectError): + with pytest.raises(ExpectedExit): + cli.main() diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index 630d1d6495..1091a80b33 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -6,7 +6,12 @@ from commitizen import cli, git from commitizen.commands.changelog import Changelog -from commitizen.exceptions import DryRunExit, NoCommitsFoundError, NoRevisionError +from commitizen.exceptions import ( + DryRunExit, + NoCommitsFoundError, + NoRevisionError, + NotAGitProjectError, +) from tests.utils import create_file_and_commit @@ -335,3 +340,12 @@ def test_changelog_with_different_tag_name_and_changelog_content( with pytest.raises(NoRevisionError): cli.main() + + +def test_changelog_in_non_git_project(tmpdir, config, mocker): + testargs = ["cz", "changelog", "--incremental"] + mocker.patch.object(sys, "argv", testargs) + + with tmpdir.as_cwd(): + with pytest.raises(NotAGitProjectError): + cli.main() diff --git a/tests/commands/test_commit_command.py b/tests/commands/test_commit_command.py index dd168bf31a..66288cecc3 100644 --- a/tests/commands/test_commit_command.py +++ b/tests/commands/test_commit_command.py @@ -10,6 +10,7 @@ DryRunExit, NoAnswersError, NoCommitBackupError, + NotAGitProjectError, NothingToCommitError, ) @@ -151,3 +152,9 @@ def test_commit_when_no_user_answer(config, mocker, capsys): with pytest.raises(NoAnswersError): commit_cmd = commands.Commit(config, {}) commit_cmd() + + +def test_commit_in_non_git_project(tmpdir, config): + with tmpdir.as_cwd(): + with pytest.raises(NotAGitProjectError): + commands.Commit(config, {}) diff --git a/tests/test_conf.py b/tests/test_conf.py index d78ed36d9b..fd9bd66c77 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -4,7 +4,6 @@ import pytest from commitizen import config, defaults, git -from commitizen.exceptions import NotAGitProjectError PYPROJECT = """ [tool.commitizen] @@ -150,14 +149,6 @@ def test_find_git_project_root(tmpdir): assert git.find_git_project_root() is None -def test_read_cfg_when_not_in_a_git_project(tmpdir): - with tmpdir.as_cwd() as _: - with pytest.raises(NotAGitProjectError) as excinfo: - config.read_cfg() - - assert NotAGitProjectError.message in str(excinfo.value) - - class TestInilConfig: def test_read_setup_cfg_without_commitizen_config(self, tmpdir): path = tmpdir.mkdir("commitizen").join("setup.cfg") From eef1e6d9cb6e9716382d41ee04e115bc47ce11ac Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Tue, 14 Jul 2020 14:47:56 +0000 Subject: [PATCH 183/427] =?UTF-8?q?bump:=20version=201.23.0=20=E2=86=92=20?= =?UTF-8?q?1.23.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a13e79ea11..c4cdae544d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v1.23.1 (2020-07-14) + +### Fix + +- Raise NotAGitProjectError only in git related command + ## v1.23.0 (2020-06-14) ### Refactor diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 282cfcb4e7..0278bb4fab 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.23.0" +__version__ = "1.23.1" diff --git a/pyproject.toml b/pyproject.toml index 53fe211777..b73d63536f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.23.0" +version = "1.23.1" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.23.0" +version = "1.23.1" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From e9ecf83136d17cf125f38f492b01cd52bf914ffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Fri, 24 Jul 2020 11:22:15 +0200 Subject: [PATCH 184/427] docs: add faq --- docs/faq.md | 28 ++++++++++++++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 29 insertions(+) create mode 100644 docs/faq.md diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 0000000000..ab6bb97fa1 --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,28 @@ +## Support for PEP621 + +PEP621 establishes a `[project]` definition inside `pyproject.toml` + +```toml +[project] +name = "spam" +version = "2020.0.0" +``` + +Commitizen **won't** use the `project.version` as a source of truth because it's a +tool aimed for any kind of project. + +If we were to use it, it would increase the complexity of the tool. Also why +wouldn't we support other project files like `cargo.toml` or `package.json`? + +Instead of supporting all the different project files, you can use `version_files` +inside `[tool.commitizen]`, and it will cheaply keep any of these project files in sync + +```toml +[tool.commitizen] +version = "2.5.1" +version_files = [ + "pyproject.toml:^version", + "cargo.toml:^version", + "package.json:\"version\":" +] +``` diff --git a/mkdocs.yml b/mkdocs.yml index 39c53d9500..5cccfd033e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -21,6 +21,7 @@ nav: - Writing commits: 'tutorials/writing_commits.md' - GitLab CI: 'tutorials/gitlab_ci.md' - Github Actions: 'tutorials/github_actions.md' + - FAQ: 'faq.md' - Exit Codes: 'exit_codes.md' - Third-Party Commitizen Templates: 'third-party-commitizen.md' - Contributing: 'contributing.md' From 4982f1d8ac169a6fa75a62ba15063405b8ca307e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Fri, 24 Jul 2020 11:22:47 +0200 Subject: [PATCH 185/427] docs: rename external links to resources --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 5cccfd033e..7089782453 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -25,7 +25,7 @@ nav: - Exit Codes: 'exit_codes.md' - Third-Party Commitizen Templates: 'third-party-commitizen.md' - Contributing: 'contributing.md' - - External Links: 'external_links.md' + - Resources: 'external_links.md' markdown_extensions: - markdown.extensions.codehilite: From 056c7663040699c820677cab82d807e951bd99b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Fri, 24 Jul 2020 11:58:54 +0200 Subject: [PATCH 186/427] docs: polish github templates - information for submitter are now comments - removed redundancy in titles, we use labels now - typos corrections --- .github/ISSUE_TEMPLATE/bug_report.md | 32 ++++++++++++++--------- .github/ISSUE_TEMPLATE/documentation.md | 9 ++++--- .github/ISSUE_TEMPLATE/feature_request.md | 12 ++++----- .github/pull_request_template.md | 32 +++++++++++++++-------- 4 files changed, 52 insertions(+), 33 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 2281f35e7d..bfd26c9265 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,30 +1,38 @@ --- name: 🛠 Bug report about: Create a report to help us improve -title: "[Bug Report] Good bug title tells us about precise symptom, not about the root cause." +title: "Good bug title tells us about precise symptom, not about the root cause." labels: "bug" assignees: "" --- ## Description -A clear and concise description of what the bug is. +<!-- A clear and concise description of what the bug is. --> -## commitizen version -x.y.z - -## Steps to Reproduce -Steps to reproduce the behavior: +## Steps to reproduce +<!-- Steps to reproduce the behavior: 1. Run ... 2. ... -3. ... +3. ... --> + +## Current behavior +<!-- What happens actually so you think this is a bug. --> -## Expected Behavior +## Desired behavior +<!-- A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. +--> -## Actual Behavior -What happens actually so you think this is a bug. +## Environment +<!-- +cz version +python --version +python3 -c "import platform; print(platform.system())" +--> -## More Information +- commitizen version: +- python version: +- operating system: diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md index d1543dc40f..f96cfff7bc 100644 --- a/.github/ISSUE_TEMPLATE/documentation.md +++ b/.github/ISSUE_TEMPLATE/documentation.md @@ -1,18 +1,19 @@ --- name: 📖 Documentation about: Suggest an improvement for the documentation of this project -title: "[Documentation] Content to be added or fixed" +title: "Content to be added or fixed" labels: "documentation" assignees: "" --- ## Type -* [ ] Conent inaccurate + +* [ ] Content inaccurate * [ ] Content missing * [ ] Typo ## URL -URL to the code we did not clearly describe or the document page where the content is inaccurate +<!-- URL to the code we did not clearly describe or the document page where the content is inaccurate --> ## Description -A clear and concise description of what content should be added or fixed +<!-- A clear and concise description of what content should be added or fixed --> diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index b43e366394..8077ccec59 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,19 +1,19 @@ --- name: 🚀 Feature request about: Suggest an idea for this project -title: "[Feature Request] <One feature request per issue>" -labels: "" +title: "<One feature request per issue>" +labels: "enhancement" assignees: "" --- ## Description -A clear and concise description for us to know your idea. +<!-- A clear and concise description for us to know your idea. --> ## Possible Solution -A clear and concise description of what you want to happen. +<!-- A clear and concise description of what you want to happen. --> ## Additional context -Add any other context or screenshots about the feature request here. +<!-- Add any other context or screenshots about the feature request here. --> ## Related Issue -If applicable, add link to existing issue also help us know better. +<!-- If applicable, add link to existing issue also help us know better. --> diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index ed2a601064..cfeab88e69 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,35 +1,45 @@ -(Thanks for sending a pull request! Please fill in the following content to let us know better about this change.) +<!-- +Thanks for sending a pull request! +Please fill in the following content to let us know better about this change. +--> ## Types of changes -Please put an `x` in the box that applies -- [ ] **Bugfix** +<!-- Please put an `x` in the box that applies --> + +- [ ] **Bug fix** - [ ] **New feature** - [ ] **Refactoring** - [ ] **Breaking change** (any change that would cause existing functionality to not work as expected) -- [ ] **Documentation Update** +- [ ] **Documentation update** - [ ] **Other (please describe)** ## Description -**Describe what the change is** -## Checklist: +<!-- Describe what the change is --> + +## Checklist + - [ ] Add test cases to all the changes you introduce - [ ] Run `./script/format` and `./script/test` locally to ensure this change passes linter check and test - [ ] Test the changes on the local machine manually - [ ] Update the documentation for the changes ## Steps to Test This Pull Request -Steps to reproduce the behavior: + +<!-- Steps to reproduce the behavior: 1. ... 2. ... -3. ... +3. ... --> ## Expected behavior -A clear and concise description of what you expected to happen + +<!-- A clear and concise description of what you expected to happen --> ## Related Issue -If applicable, reference to the issue related to this pull request. + +<!-- If applicable, reference to the issue related to this pull request. --> ## Additional context -Add any other context or screenshots about the pull request here. + +<!-- Add any other context or screenshots about the pull request here. --> From eeaf7593556363def6fac614217565b36bf9106d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Fri, 24 Jul 2020 12:19:04 +0200 Subject: [PATCH 187/427] docs: set label for feature request as 'feature' instead of 'enhacement' --- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 8077ccec59..b9d48126a4 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -2,7 +2,7 @@ name: 🚀 Feature request about: Suggest an idea for this project title: "<One feature request per issue>" -labels: "enhancement" +labels: "feature" assignees: "" --- From 7b409cc4405b775a08f81eff796a0270b39d9e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Fri, 24 Jul 2020 12:22:56 +0200 Subject: [PATCH 188/427] docs: add new article --- docs/external_links.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/external_links.md b/docs/external_links.md index 97d56442bb..b31ac85bb3 100644 --- a/docs/external_links.md +++ b/docs/external_links.md @@ -1,9 +1,14 @@ ## Talks -* commitizen-tools: What can we gain from crafting a git message convention - * Speaker: Wei Lee - * Occasion: Taipey.py 2020 June Meetup, Remote Python Pizza 2020 - * Material - * [slides](https://speakerdeck.com/leew/commitizen-tools-what-can-we-gain-from-crafting-a-git-message-convention-at-taipey-dot-py) + +- commitizen-tools: What can we gain from crafting a git message convention + - Speaker: Wei Lee + - Occasion: Taipey.py 2020 June Meetup, Remote Python Pizza 2020 + - Material + - [slides](https://speakerdeck.com/leew/commitizen-tools-what-can-we-gain-from-crafting-a-git-message-convention-at-taipey-dot-py) ## Articles -* [Python Table Manners - Commitizen: 規格化 commit message](https://lee-w.github.io/posts/tech/2020/03/python-table-manners-commitizen/) (Written in Traditional Mandarin) + +- [Python Table Manners - Commitizen: 規格化 commit message](https://lee-w.github.io/posts/tech/2020/03/python-table-manners-commitizen/) (Written in Traditional Mandarin) +- [Automating semantic release with commitizen](http://woile.github.io/posts/automating-semver-releases-with-commitizen/) (English) + +> If you have written about commitizen, you can make a PR to add the link here 💪 From e37e3e64012814b726c3670abb6387da33660293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Fri, 24 Jul 2020 14:41:11 +0200 Subject: [PATCH 189/427] docs(README.md): make documentation more visible --- docs/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 393ea5bc5e..189504fb3b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,7 +9,11 @@ versions](https://img.shields.io/pypi/pyversions/commitizen.svg?style=flat-squar ![Using commitizen cli](images/demo.gif) -View full [documentation](https://commitizen-tools.github.io/commitizen/). +--- + +**Documentation**: https://commitizen-tools.github.io/ + +--- ## About From e4a21bee1dcfa96effa0828a5f69fde449c00bd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 25 Jul 2020 11:11:23 +0200 Subject: [PATCH 190/427] refactor(cmd): add return code to Command --- commitizen/cmd.py | 4 +++- tests/commands/test_commit_command.py | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/commitizen/cmd.py b/commitizen/cmd.py index 67c7cf6bd0..fb041c9faf 100644 --- a/commitizen/cmd.py +++ b/commitizen/cmd.py @@ -7,6 +7,7 @@ class Command(NamedTuple): err: str stdout: bytes stderr: bytes + return_code: int def run(cmd: str) -> Command: @@ -18,4 +19,5 @@ def run(cmd: str) -> Command: stdin=subprocess.PIPE, ) stdout, stderr = process.communicate() - return Command(stdout.decode(), stderr.decode(), stdout, stderr) + return_code = process.returncode + return Command(stdout.decode(), stderr.decode(), stdout, stderr, return_code) diff --git a/tests/commands/test_commit_command.py b/tests/commands/test_commit_command.py index 66288cecc3..b01cadd7d5 100644 --- a/tests/commands/test_commit_command.py +++ b/tests/commands/test_commit_command.py @@ -34,7 +34,7 @@ def test_commit(config, mocker): } commit_mock = mocker.patch("commitizen.git.commit") - commit_mock.return_value = cmd.Command("success", "", "", "") + commit_mock.return_value = cmd.Command("success", "", "", "", 0) success_mock = mocker.patch("commitizen.out.success") commands.Commit(config, {})() @@ -44,7 +44,7 @@ def test_commit(config, mocker): @pytest.mark.usefixtures("staging_is_clean") def test_commit_retry_fails_no_backup(config, mocker): commit_mock = mocker.patch("commitizen.git.commit") - commit_mock.return_value = cmd.Command("success", "", "", "") + commit_mock.return_value = cmd.Command("success", "", "", "", 0) with pytest.raises(NoCommitBackupError) as excinfo: commands.Commit(config, {"retry": True})() @@ -65,7 +65,7 @@ def test_commit_retry_works(config, mocker): } commit_mock = mocker.patch("commitizen.git.commit") - commit_mock.return_value = cmd.Command("", "error", "", "") + commit_mock.return_value = cmd.Command("", "error", "", "", 0) error_mock = mocker.patch("commitizen.out.error") with pytest.raises(CommitError): @@ -79,7 +79,7 @@ def test_commit_retry_works(config, mocker): # Previous commit failed, so retry should pick up the backup commit # commit_mock = mocker.patch("commitizen.git.commit") - commit_mock.return_value = cmd.Command("success", "", "", "") + commit_mock.return_value = cmd.Command("success", "", "", "", 0) success_mock = mocker.patch("commitizen.out.success") commands.Commit(config, {"retry": True})() From bf16b51f0055cc19dbe3e7908776b907cfec871c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 25 Jul 2020 11:49:34 +0200 Subject: [PATCH 191/427] fix(commands/commit): use return_code to raise commit error, not stderr --- commitizen/commands/commit.py | 5 ++--- tests/commands/test_commit_command.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index 33b607ae45..09fb2cbbef 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -75,7 +75,7 @@ def __call__(self): c = git.commit(m) - if c.err: + if c.return_code != 0: out.error(c.err) # Create commit backup @@ -86,10 +86,9 @@ def __call__(self): if "nothing added" in c.out or "no changes added to commit" in c.out: out.error(c.out) - elif c.err: - out.error(c.err) else: with contextlib.suppress(FileNotFoundError): os.remove(self.temp_file) + out.write(c.err) out.write(c.out) out.success("Commit successful!") diff --git a/tests/commands/test_commit_command.py b/tests/commands/test_commit_command.py index b01cadd7d5..7d56f08752 100644 --- a/tests/commands/test_commit_command.py +++ b/tests/commands/test_commit_command.py @@ -65,7 +65,7 @@ def test_commit_retry_works(config, mocker): } commit_mock = mocker.patch("commitizen.git.commit") - commit_mock.return_value = cmd.Command("", "error", "", "", 0) + commit_mock.return_value = cmd.Command("", "error", "", "", 9) error_mock = mocker.patch("commitizen.out.error") with pytest.raises(CommitError): From ce8264e6632c29294bf31090dec3f46da8b5f6db Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 25 Jul 2020 18:12:26 +0800 Subject: [PATCH 192/427] fix(bump): add changelog file into stage when running `cz bump --changelog` --- commitizen/commands/bump.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index d656a1b57a..5d3ffb3e90 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -3,7 +3,7 @@ import questionary from packaging.version import Version -from commitizen import bump, factory, git, out +from commitizen import bump, cmd, factory, git, out from commitizen.commands.changelog import Changelog from commitizen.config import BaseConfig from commitizen.exceptions import ( @@ -142,7 +142,7 @@ def __call__(self): # noqa: C901 raise ExpectedExit() if self.changelog: - changelog = Changelog( + changelog_cmd = Changelog( self.config, { "unreleased_version": new_tag_version, @@ -150,7 +150,8 @@ def __call__(self): # noqa: C901 "dry_run": dry_run, }, ) - changelog() + changelog_cmd() + c = cmd.run(f"git add {changelog_cmd.file_name}") self.config.set_key("version", new_version.public) c = git.commit(message, args=self._get_commit_args()) From 24c6862a761ab24ab522daa49488800f38c666c2 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sat, 25 Jul 2020 10:24:05 +0000 Subject: [PATCH 193/427] =?UTF-8?q?bump:=20version=201.23.1=20=E2=86=92=20?= =?UTF-8?q?1.23.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4cdae544d..454b2e9e24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v1.23.2 (2020-07-25) + +### Fix + +- **bump**: add changelog file into stage when running `cz bump --changelog` + ## v1.23.1 (2020-07-14) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 0278bb4fab..35026e4983 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.23.1" +__version__ = "1.23.2" diff --git a/pyproject.toml b/pyproject.toml index b73d63536f..b855a89b7c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.23.1" +version = "1.23.2" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.23.1" +version = "1.23.2" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 107fa257f3ad3edd0f88ff68e223642765b9bfda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 25 Jul 2020 15:20:13 +0200 Subject: [PATCH 194/427] fix(commands/bump): use `return_code` in commands used by bump --- commitizen/commands/bump.py | 4 ++-- tests/commands/test_bump_command.py | 28 ++++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index d656a1b57a..61c63a2e9f 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -154,10 +154,10 @@ def __call__(self): # noqa: C901 self.config.set_key("version", new_version.public) c = git.commit(message, args=self._get_commit_args()) - if c.err: + if c.return_code != 0: raise BumpCommitFailedError(f'git.commit error: "{c.err.strip()}"') c = git.tag(new_tag_version) - if c.err: + if c.return_code != 0: raise BumpTagFailedError(c.err) out.success("Done!") diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index 511415c97c..cc76f15a9b 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -4,7 +4,7 @@ from commitizen import cli, cmd, git from commitizen.exceptions import ( - BumpCommitFailedError, + BumpTagFailedError, CurrentVersionNotFoundError, DryRunExit, ExpectedExit, @@ -71,6 +71,7 @@ def test_bump_command(mocker): @pytest.mark.usefixtures("tmp_commitizen_project") def test_bump_on_git_with_hooks_no_verify_disabled(mocker): + """Bump commit without --no-verify""" cmd.run("mkdir .git/hooks") with open(".git/hooks/pre-commit", "w") as f: f.write("#!/usr/bin/env bash\n" 'echo "0.1.0"') @@ -82,10 +83,29 @@ def test_bump_on_git_with_hooks_no_verify_disabled(mocker): testargs = ["cz", "bump", "--yes"] mocker.patch.object(sys, "argv", testargs) - with pytest.raises(BumpCommitFailedError) as excinfo: - cli.main() + cli.main() + + tag_exists = git.tag_exist("0.2.0") + assert tag_exists is True + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_bump_tag_exists_raises_exception(mocker): + cmd.run("mkdir .git/hooks") + with open(".git/hooks/post-commit", "w") as f: + f.write("#!/usr/bin/env bash\n" "exit 9") + cmd.run("chmod +x .git/hooks/post-commit") + + # MINOR + create_file_and_commit("feat: new file") + git.tag("0.2.0") - assert 'git.commit error: "0.1.0"' in str(excinfo.value) + testargs = ["cz", "bump", "--yes"] + mocker.patch.object(sys, "argv", testargs) + + with pytest.raises(BumpTagFailedError) as excinfo: + cli.main() + assert "fatal: tag '0.2.0' already exists" in str(excinfo.value) @pytest.mark.usefixtures("tmp_commitizen_project") From ef5450d5970d46c5d4d9bd05f6093a8871e14c9a Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sat, 25 Jul 2020 14:24:13 +0000 Subject: [PATCH 195/427] =?UTF-8?q?bump:=20version=201.23.2=20=E2=86=92=20?= =?UTF-8?q?1.23.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 11 +++++++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 454b2e9e24..9deccac577 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## v1.23.3 (2020-07-25) + +### Fix + +- **commands/bump**: use `return_code` in commands used by bump +- **commands/commit**: use return_code to raise commit error, not stderr + +### Refactor + +- **cmd**: add return code to Command + ## v1.23.2 (2020-07-25) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 35026e4983..d5ca089f26 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.23.2" +__version__ = "1.23.3" diff --git a/pyproject.toml b/pyproject.toml index b855a89b7c..0f286d5053 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.23.2" +version = "1.23.3" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.23.2" +version = "1.23.3" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 1e16d6c9262ccb5da363649ed2b4e6935795ac98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 25 Jul 2020 16:54:48 +0200 Subject: [PATCH 196/427] test(bump_command): remove english text in favor of just the tag number --- tests/commands/test_bump_command.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index cc76f15a9b..f299e88afe 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -105,7 +105,7 @@ def test_bump_tag_exists_raises_exception(mocker): with pytest.raises(BumpTagFailedError) as excinfo: cli.main() - assert "fatal: tag '0.2.0' already exists" in str(excinfo.value) + assert "0.2.0" in str(excinfo.value) # This should be a fatal error @pytest.mark.usefixtures("tmp_commitizen_project") From d4a4bda6d2d729395411fe1c6fb76effd9474585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 25 Jul 2020 17:08:21 +0200 Subject: [PATCH 197/427] refactor(changelog): remove pkg_resources dependency --- commitizen/changelog.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/commitizen/changelog.py b/commitizen/changelog.py index 620c6ade29..52b8cf786b 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -19,10 +19,10 @@ Extra: - [x] Generate full or partial changelog - [x] Include in tree from file all the extra comments added manually -- [ ] Add unreleased value -- [ ] hook after message is parsed (add extra information like hyperlinks) -- [ ] hook after changelog is generated (api calls) -- [ ] add support for change_type maps +- [x] Add unreleased value +- [x] hook after message is parsed (add extra information like hyperlinks) +- [x] hook after changelog is generated (api calls) +- [x] add support for change_type maps """ import os import re @@ -30,8 +30,7 @@ from datetime import date from typing import Callable, Dict, Iterable, List, Optional -import pkg_resources -from jinja2 import Template +from jinja2 import Environment, PackageLoader from commitizen import defaults from commitizen.git import GitCommit, GitTag @@ -130,10 +129,9 @@ def generate_tree_from_commits( def render_changelog(tree: Iterable) -> str: - template_file = pkg_resources.resource_string( - __name__, "templates/keep_a_changelog_template.j2" - ).decode("utf-8") - jinja_template = Template(template_file, trim_blocks=True) + loader = PackageLoader("commitizen", "templates") + env = Environment(loader=loader, trim_blocks=True) + jinja_template = env.get_template("keep_a_changelog_template.j2") changelog: str = jinja_template.render(tree=tree) return changelog From d3e4a842b5968d9d94cb36b356b103e291a81fb0 Mon Sep 17 00:00:00 2001 From: jtpavlock <jtpavlock@gmail.com> Date: Sat, 25 Jul 2020 16:37:46 -0500 Subject: [PATCH 198/427] Add `cz check --rev-range` to the docs Expands on the different use cases for using `cz check` as well --- docs/check.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/check.md b/docs/check.md index af1c2a56dd..446326ada5 100644 --- a/docs/check.md +++ b/docs/check.md @@ -1,7 +1,9 @@ ## About This feature checks whether the commit message follows the given committing rules. -You can use either of the following methods to enforce the check. + +## Checking before the commit +To automatically check a commit message prior to committing, you can use a [git hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks). There are two common methods for installing the hook: ### Method 1: Add git hook through [pre-commit](https://pre-commit.com/) @@ -60,3 +62,10 @@ Each time you create a commit, automatically, this hook will analyze it. If the commit message is invalid, it'll be rejected. The commit should follow the given committing rules; otherwise, it won't be accepted. + +## Checking after the commit +If you'd like to check a commit's message after it has already been created, then you can specify the range of commits to check with `--rev-range REV_RANGE` + +For example, if you'd like to check all commits on a branch, you can use `--rev-range master..HEAD`. Or, if you'd like to check all commits starting from when you first implemented commit message linting, you can use `--rev-range <first_commit_sha>..HEAD`. + +For more info on how git commit ranges work, you can check the [git documentation](https://git-scm.com/book/en/v2/Git-Tools-Revision-Selection#_commit_ranges). From ab91e62eb0a3f70d00cbdaf73ac3f29bffc1ff52 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sun, 26 Jul 2020 08:31:15 +0000 Subject: [PATCH 199/427] =?UTF-8?q?bump:=20version=201.23.3=20=E2=86=92=20?= =?UTF-8?q?1.23.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9deccac577..62ea3f9098 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v1.23.4 (2020-07-26) + +### Refactor + +- **changelog**: remove pkg_resources dependency + ## v1.23.3 (2020-07-25) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index d5ca089f26..2c9badbeb6 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.23.3" +__version__ = "1.23.4" diff --git a/pyproject.toml b/pyproject.toml index 0f286d5053..5075d5641d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.23.3" +version = "1.23.4" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.23.3" +version = "1.23.4" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 95ec2615b1d58fac3bbba2f812964f265c9f1674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sun, 26 Jul 2020 10:47:43 +0200 Subject: [PATCH 200/427] feat: add author and author_email to git commit Extra useful information for hooks Closes #188 --- commitizen/git.py | 17 +++-- tests/test_changelog.py | 143 ++++++++++++++++++++++++++++++++++++++-- tests/test_git.py | 20 ++++++ 3 files changed, 171 insertions(+), 9 deletions(-) diff --git a/commitizen/git.py b/commitizen/git.py index ac33181ce6..66b902950f 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -18,10 +18,14 @@ def __eq__(self, other) -> bool: class GitCommit(GitObject): - def __init__(self, rev, title, body=""): + def __init__( + self, rev, title, body: str = "", author: str = "", author_email: str = "" + ): self.rev = rev.strip() self.title = title.strip() self.body = body.strip() + self.author = author.strip() + self.author_email = author_email.strip() @property def message(self): @@ -59,7 +63,7 @@ def get_commits( start: Optional[str] = None, end: str = "HEAD", *, - log_format: str = "%H%n%s%n%b", + log_format: str = "%H%n%s%n%an%n%ae%n%b", delimiter: str = "----------commit-delimiter----------", args: str = "", ) -> List[GitCommit]: @@ -79,11 +83,14 @@ def get_commits( rev_and_commit = rev_and_commit.strip() if not rev_and_commit: continue - rev, title, *body_list = rev_and_commit.split("\n") - + rev, title, author, author_email, *body_list = rev_and_commit.split("\n") if rev_and_commit: git_commit = GitCommit( - rev=rev.strip(), title=title.strip(), body="\n".join(body_list).strip() + rev=rev.strip(), + title=title.strip(), + body="\n".join(body_list).strip(), + author=author, + author_email=author_email, ) git_commits.append(git_commit) return git_commits diff --git a/tests/test_changelog.py b/tests/test_changelog.py index 9675802e43..b1dc1dc0e7 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -7,316 +7,442 @@ "rev": "141ee441c9c9da0809c554103a558eb17c30ed17", "title": "bump: version 1.1.1 → 1.2.0", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "6c4948501031b7d6405b54b21d3d635827f9421b", "title": "docs: how to create custom bumps", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "ddd220ad515502200fe2dde443614c1075d26238", "title": "feat: custom cz plugins now support bumping version", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "ad17acff2e3a2e141cbc3c6efd7705e4e6de9bfc", "title": "docs: added bump gif", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "56c8a8da84e42b526bcbe130bd194306f7c7e813", "title": "bump: version 1.1.0 → 1.1.1", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "74c6134b1b2e6bb8b07ed53410faabe99b204f36", "title": "refactor: changed stdout statements", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "cbc7b5f22c4e74deff4bc92d14e19bd93524711e", "title": "fix(bump): commit message now fits better with semver", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "1ba46f2a63cb9d6e7472eaece21528c8cd28b118", "title": "fix: conventional commit 'breaking change' in body instead of title", "body": "closes #16", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "c35dbffd1bb98bb0b3d1593797e79d1c3366af8f", "title": "refactor(schema): command logic removed from commitizen base", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "25313397a4ac3dc5b5c986017bee2a614399509d", "title": "refactor(info): command logic removed from commitizen base", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "d2f13ac41b4e48995b3b619d931c82451886e6ff", "title": "refactor(example): command logic removed from commitizen base", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "d839e317e5b26671b010584ad8cc6bf362400fa1", "title": "refactor(commit): moved most of the commit logic to the commit command", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "12d0e65beda969f7983c444ceedc2a01584f4e08", "title": "docs(README): updated documentation url)", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "fb4c85abe51c228e50773e424cbd885a8b6c610d", "title": "docs: mkdocs documentation", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "17efb44d2cd16f6621413691a543e467c7d2dda6", "title": "Bump version 1.0.0 → 1.1.0", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "6012d9eecfce8163d75c8fff179788e9ad5347da", "title": "test: fixed issues with conf", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "0c7fb0ca0168864dfc55d83c210da57771a18319", "title": "docs(README): some new information about bump", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "cb1dd2019d522644da5bdc2594dd6dee17122d7f", "title": "feat: new working bump command", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "9c7450f85df6bf6be508e79abf00855a30c3c73c", "title": "feat: create version tag", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "9f3af3772baab167e3fd8775d37f041440184251", "title": "docs: added new changelog", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "b0d6a3defbfde14e676e7eb34946409297d0221b", "title": "feat: update given files with new version", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "d630d07d912e420f0880551f3ac94e933f9d3beb", "title": "fix: removed all from commit", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "1792b8980c58787906dbe6836f93f31971b1ec2d", "title": "feat(config): new set key, used to set version to cfg", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "52def1ea3555185ba4b936b463311949907e31ec", "title": "feat: support for pyproject.toml", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "3127e05077288a5e2b62893345590bf1096141b7", "title": "feat: first semantic version bump implementation", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "fd480ed90a80a6ffa540549408403d5b60d0e90c", "title": "fix: fix config file not working", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "e4840a059731c0bf488381ffc77e989e85dd81ad", "title": "refactor: added commands folder, better integration with decli", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "aa44a92d68014d0da98965c0c2cb8c07957d4362", "title": "Bump version: 1.0.0b2 → 1.0.0", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "58bb709765380dbd46b74ce6e8978515764eb955", "title": "docs(README): new badges", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "97afb0bb48e72b6feca793091a8a23c706693257", "title": "Merge pull request #10 from Woile/feat/decli", "body": "Feat/decli", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "9cecb9224aa7fa68d4afeac37eba2a25770ef251", "title": "style: black to files", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "f5781d1a2954d71c14ade2a6a1a95b91310b2577", "title": "ci: added travis", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "80105fb3c6d45369bc0cbf787bd329fba603864c", "title": "refactor: removed delegator, added decli and many tests", "body": "BREAKING CHANGE: API is stable", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "a96008496ffefb6b1dd9b251cb479eac6a0487f7", "title": "docs: updated test command", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "aab33d13110f26604fb786878856ec0b9e5fc32b", "title": "Bump version: 1.0.0b1 → 1.0.0b2", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "b73791563d2f218806786090fb49ef70faa51a3a", "title": "docs(README): updated to reflect current state", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "7aa06a454fb717408b3657faa590731fb4ab3719", "title": "Merge pull request #9 from Woile/dev", "body": "feat: py3 only, tests and conventional commits 1.0", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "7c7e96b723c2aaa1aec3a52561f680adf0b60e97", "title": "Bump version: 0.9.11 → 1.0.0b1", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "ed830019581c83ba633bfd734720e6758eca6061", "title": "feat: py3 only, tests and conventional commits 1.0", "body": "more tests\npyproject instead of Pipfile\nquestionary instead of whaaaaat (promptkit 2.0.0 support)", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "c52eca6f74f844ab3ffbde61d98ef96071e132b7", "title": "Bump version: 0.9.10 → 0.9.11", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "0326652b2657083929507ee66d4d1a0899e861ba", "title": "fix(config): load config reads in order without failing if there is no commitizen section", "body": "Closes #8", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "b3f89892222340150e32631ae6b7aab65230036f", "title": "Bump version: 0.9.9 → 0.9.10", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "5e837bf8ef0735193597372cd2d85e31a8f715b9", "title": "fix: parse scope (this is my punishment for not having tests)", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "684e0259cc95c7c5e94854608cd3dcebbd53219e", "title": "Bump version: 0.9.8 → 0.9.9", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "ca38eac6ff09870851b5c76a6ff0a2a8e5ecda15", "title": "fix: parse scope empty", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "64168f18d4628718c49689ee16430549e96c5d4b", "title": "Bump version: 0.9.7 → 0.9.8", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "9d4def716ef235a1fa5ae61614366423fbc8256f", "title": "fix(scope): parse correctly again", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "33b0bf1a0a4dc60aac45ed47476d2e5473add09e", "title": "Bump version: 0.9.6 → 0.9.7", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "696885e891ec35775daeb5fec3ba2ab92c2629e1", "title": "fix(scope): parse correctly", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "bef4a86761a3bda309c962bae5d22ce9b57119e4", "title": "Bump version: 0.9.5 → 0.9.6", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "72472efb80f08ee3fd844660afa012c8cb256e4b", "title": "refactor(conventionalCommit): moved filters to questions instead of message", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "b5561ce0ab3b56bb87712c8f90bcf37cf2474f1b", "title": "fix(manifest): included missing files", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "3e31714dc737029d96898f412e4ecd2be1bcd0ce", "title": "Bump version: 0.9.4 → 0.9.5", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "9df721e06595fdd216884c36a28770438b4f4a39", "title": "fix(config): home path for python versions between 3.0 and 3.5", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "0cf6ada372470c8d09e6c9e68ebf94bbd5a1656f", "title": "Bump version: 0.9.3 → 0.9.4", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "973c6b3e100f6f69a3fe48bd8ee55c135b96c318", "title": "feat(cli): added version", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "dacc86159b260ee98eb5f57941c99ba731a01399", "title": "Bump version: 0.9.2 → 0.9.3", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "4368f3c3cbfd4a1ced339212230d854bc5bab496", "title": "feat(committer): conventional commit is a bit more intelligent now", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "da94133288727d35dae9b91866a25045038f2d38", "title": "docs(README): motivation", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "1541f54503d2e1cf39bd777c0ca5ab5eb78772ba", "title": "Bump version: 0.9.1 → 0.9.2", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "ddc855a637b7879108308b8dbd85a0fd27c7e0e7", "title": "refactor: renamed conventional_changelog to conventional_commits, not backward compatible", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "46e9032e18a819e466618c7a014bcb0e9981af9e", "title": "Bump version: 0.9.0 → 0.9.1", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, { "rev": "0fef73cd7dc77a25b82e197e7c1d3144a58c1350", "title": "fix(setup.py): future is now required for every python version", "body": "", + "author": "Commitizen", + "author_email": "author@cz.dev", }, ] @@ -345,7 +471,13 @@ @pytest.fixture # type: ignore def gitcommits() -> list: commits = [ - git.GitCommit(commit["rev"], commit["title"], commit["body"]) + git.GitCommit( + commit["rev"], + commit["title"], + commit["body"], + commit["author"], + commit["author_email"], + ) for commit in COMMITS_DATA ] return commits @@ -716,8 +848,10 @@ def test_render_changelog_with_change_type(gitcommits, tags): def test_render_changelog_with_changelog_message_builder_hook(gitcommits, tags): - def changelog_message_builder_hook(message: dict, _) -> dict: - message["message"] = f"{message['message']} [link](github.com/232323232)" + def changelog_message_builder_hook(message: dict, commit: git.GitCommit) -> dict: + message[ + "message" + ] = f"{message['message']} [link](github.com/232323232) {commit.author} {commit.author_email}" return message parser = defaults.commit_parser @@ -730,4 +864,5 @@ def changelog_message_builder_hook(message: dict, _) -> dict: changelog_message_builder_hook=changelog_message_builder_hook, ) result = changelog.render_changelog(tree) - assert "[link](github.com/232323232)" in result + + assert "[link](github.com/232323232) Commitizen author@cz.dev" in result diff --git a/tests/test_git.py b/tests/test_git.py index 3a6638b329..0fa22df12e 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -1,4 +1,7 @@ +import pytest + from commitizen import git +from tests.utils import create_file_and_commit class FakeCommand: @@ -54,3 +57,20 @@ def test_git_message_with_empty_body(): commit = git.GitCommit("test_rev", "Some Title", body="") assert commit.message == commit_title + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_get_commits(): + create_file_and_commit("feat(users): add username") + create_file_and_commit("fix: username exception") + commits = git.get_commits() + assert len(commits) == 2 + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_get_commits_author_and_email(): + create_file_and_commit("fix: username exception") + commit = git.get_commits()[0] + + assert commit.author is not "" + assert "@" in commit.author_email From b01119e7d99cdbb51c7af8445a5a2a066f18f10d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sun, 26 Jul 2020 10:52:00 +0200 Subject: [PATCH 201/427] docs: add author and author_email example --- docs/customization.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/customization.md b/docs/customization.md index 20f9ffb9fe..0602b9cecb 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -60,14 +60,14 @@ message = "Do you want to add body message in commit?" #### Detailed `questions` content -| Parameter | Type | Default | Description | -| --------- | ------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `type` | `str` | `None` | The type of questions. Valid type: `list`, `input` and etc. [See More](https://github.com/tmbo/questionary#different-question-types) | -| `name` | `str` | `None` | The key for the value answered by user. It's used in `message_template` | -| `message` | `str` | `None` | Detail description for the question. | +| Parameter | Type | Default | Description | +| --------- | ------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| `type` | `str` | `None` | The type of questions. Valid type: `list`, `input` and etc. [See More](https://github.com/tmbo/questionary#different-question-types) | +| `name` | `str` | `None` | The key for the value answered by user. It's used in `message_template` | +| `message` | `str` | `None` | Detail description for the question. | | `choices` | `list` | `None` | (OPTIONAL) The choices when `type = list`. Either use a list of values or a list of dicitionaries with `name` and `value` keys. See examples above. | -| `default` | `Any` | `None` | (OPTIONAL) The default value for this question. | -| `filter` | `str` | `None` | (Optional) Validator for user's answer. **(Work in Progress)** | +| `default` | `Any` | `None` | (OPTIONAL) The default value for this question. | +| `filter` | `str` | `None` | (Optional) Validator for user's answer. **(Work in Progress)** | ## 2. Customize through customizing a class @@ -206,13 +206,13 @@ cz -n cz_strange bump The changelog generator should just work in a very basic manner without touching anything. You can customize it of course, and this are the variables you need to add to your custom `BaseCommitizen`. -| Parameter | Type | Required | Description | -| ------------------- | ------------------------------------------------------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `commit_parser` | `str` | NO | Regex which should provide the variables explained in the [changelog description][changelog-des] | -| `changelog_pattern` | `str` | NO | Regex to validate the commits, this is useful to skip commits that don't meet your rulling standards like a Merge. Usually the same as bump_pattern | -| `change_type_map` | `dict` | NO | Convert the title of the change type that will appear in the changelog, if a value is not found, the original will be provided | -| `changelog_message_builder_hook` | `method: (dict, git.GitCommit) -> dict` | NO | Customize with extra information your message output, like adding links, this function is executed per parsed commit. | -| `changelog_hook` | `method: (full_changelog: str, partial_changelog: Optional[str]) -> str` | NO | Receives the whole and partial (if used incremental) changelog. Useful to send slack messages or notify a compliance department. Must return the full_changelog | +| Parameter | Type | Required | Description | +| -------------------------------- | ------------------------------------------------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `commit_parser` | `str` | NO | Regex which should provide the variables explained in the [changelog description][changelog-des] | +| `changelog_pattern` | `str` | NO | Regex to validate the commits, this is useful to skip commits that don't meet your rulling standards like a Merge. Usually the same as bump_pattern | +| `change_type_map` | `dict` | NO | Convert the title of the change type that will appear in the changelog, if a value is not found, the original will be provided | +| `changelog_message_builder_hook` | `method: (dict, git.GitCommit) -> dict` | NO | Customize with extra information your message output, like adding links, this function is executed per parsed commit. Each GitCommit contains the following attrs: `rev`, `title`, `body`, `author`, `author_email` | +| `changelog_hook` | `method: (full_changelog: str, partial_changelog: Optional[str]) -> str` | NO | Receives the whole and partial (if used incremental) changelog. Useful to send slack messages or notify a compliance department. Must return the full_changelog | ```python from commitizen.cz.base import BaseCommitizen @@ -232,7 +232,7 @@ class StrangeCommitizen(BaseCommitizen): def changelog_message_builder_hook(self, parsed_message: dict, commit: git.GitCommit) -> dict: rev = commit.rev m = parsed_message["message"] - parsed_message["message"] = f"{m} {rev}" + parsed_message["message"] = f"{m} {rev} [{commit.author}]({commit.author_email})" return parsed_message def changelog_hook(self, full_changelog: str, partial_changelog: Optional[str]) -> str: From 20449e9a6b6bd4500677c2ba038b07ae7f90637a Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sun, 26 Jul 2020 08:58:17 +0000 Subject: [PATCH 202/427] =?UTF-8?q?bump:=20version=201.23.4=20=E2=86=92=20?= =?UTF-8?q?1.24.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62ea3f9098..816c1033de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v1.24.0 (2020-07-26) + +### Feat + +- add author and author_email to git commit + ## v1.23.4 (2020-07-26) ### Refactor diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 2c9badbeb6..4404cab319 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.23.4" +__version__ = "1.24.0" diff --git a/pyproject.toml b/pyproject.toml index 5075d5641d..e32016ee88 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.23.4" +version = "1.24.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.23.4" +version = "1.24.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 9b911e3b78f1f6594b56be589f58436ec8696e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sun, 26 Jul 2020 15:25:29 +0200 Subject: [PATCH 203/427] feat(conventional_commits): use and proper support for conventional commits v1.0.0 --- commitizen/changelog.py | 4 +- .../conventional_commits.py | 16 ++++---- tests/commands/test_changelog_command.py | 40 +++++++++++++++++++ tests/test_cz_conventional_commits.py | 22 +++++++++- 4 files changed, 70 insertions(+), 12 deletions(-) diff --git a/commitizen/changelog.py b/commitizen/changelog.py index 52b8cf786b..9084561c15 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -73,7 +73,7 @@ def generate_tree_from_commits( changelog_message_builder_hook: Optional[Callable] = None, ) -> Iterable[Dict]: pat = re.compile(changelog_pattern) - map_pat = re.compile(commit_parser) + map_pat = re.compile(commit_parser, re.MULTILINE) # Check if the latest commit is not tagged latest_commit = commits[0] current_tag: Optional[GitTag] = get_commit_tag(latest_commit, tags) @@ -109,7 +109,7 @@ def generate_tree_from_commits( continue message = map_pat.match(commit.message) - message_body = map_pat.match(commit.body) + message_body = map_pat.search(commit.body) if message: parsed_message: Dict = message.groupdict() # change_type becomes optional by providing None diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index e3fbb8c269..0a95a09199 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -114,12 +114,6 @@ def questions(self) -> List[Dict[str, Any]]: "Imperative, lower case and no final dot:\n" ), }, - { - "type": "confirm", - "message": "Is this a BREAKING CHANGE? Correlates with MAJOR in SemVer", - "name": "is_breaking_change", - "default": False, - }, { "type": "input", "name": "body", @@ -129,6 +123,12 @@ def questions(self) -> List[Dict[str, Any]]: ), "filter": multiple_line_breaker, }, + { + "type": "confirm", + "message": "Is this a BREAKING CHANGE? Correlates with MAJOR in SemVer", + "name": "is_breaking_change", + "default": False, + }, { "type": "input", "name": "footer", @@ -150,10 +150,10 @@ def message(self, answers: dict) -> str: if scope: scope = f"({scope})" - if is_breaking_change: - body = f"BREAKING CHANGE: {body}" if body: body = f"\n\n{body}" + if is_breaking_change: + footer = f"BREAKING CHANGE: {footer}" if footer: footer = f"\n\n{footer}" diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index 1091a80b33..09a96dfd72 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -349,3 +349,43 @@ def test_changelog_in_non_git_project(tmpdir, config, mocker): with tmpdir.as_cwd(): with pytest.raises(NotAGitProjectError): cli.main() + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_breaking_change_content_v1_beta(mocker, capsys): + commit_message = ( + "feat(users): email pattern corrected\n\n" + "BREAKING CHANGE: migrate by renaming user to users\n\n" + "footer content" + ) + create_file_and_commit(commit_message) + testargs = ["cz", "changelog", "--dry-run"] + mocker.patch.object(sys, "argv", testargs) + with pytest.raises(DryRunExit): + cli.main() + out, _ = capsys.readouterr() + + assert out == ( + "## Unreleased\n\n### Feat\n\n- **users**: email pattern corrected\n\n" + "### BREAKING CHANGE\n\n- migrate by renaming user to users\n\n" + ) + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_breaking_change_content_v1(mocker, capsys): + commit_message = ( + "feat(users): email pattern corrected\n\n" + "body content\n\n" + "BREAKING CHANGE: migrate by renaming user to users" + ) + create_file_and_commit(commit_message) + testargs = ["cz", "changelog", "--dry-run"] + mocker.patch.object(sys, "argv", testargs) + with pytest.raises(DryRunExit): + cli.main() + out, _ = capsys.readouterr() + + assert out == ( + "## Unreleased\n\n### Feat\n\n- **users**: email pattern corrected\n\n" + "### BREAKING CHANGE\n\n- migrate by renaming user to users\n\n" + ) diff --git a/tests/test_cz_conventional_commits.py b/tests/test_cz_conventional_commits.py index de6a3c30d4..62eef11a19 100644 --- a/tests/test_cz_conventional_commits.py +++ b/tests/test_cz_conventional_commits.py @@ -82,14 +82,32 @@ def test_long_answer(config): "prefix": "fix", "scope": "users", "subject": "email pattern corrected", - "is_breaking_change": True, + "is_breaking_change": False, "body": "complete content", "footer": "closes #24", } message = conventional_commits.message(answers) assert ( message - == "fix(users): email pattern corrected\n\nBREAKING CHANGE: complete content\n\ncloses #24" # noqa + == "fix(users): email pattern corrected\n\ncomplete content\n\ncloses #24" # noqa + ) + + +def test_breaking_change_in_footer(config): + conventional_commits = ConventionalCommitsCz(config) + answers = { + "prefix": "fix", + "scope": "users", + "subject": "email pattern corrected", + "is_breaking_change": True, + "body": "complete content", + "footer": "migrate by renaming user to users", + } + message = conventional_commits.message(answers) + print(message) + assert ( + message + == "fix(users): email pattern corrected\n\ncomplete content\n\nBREAKING CHANGE: migrate by renaming user to users" # noqa ) From 16e832e248f9cfb1cbf74a827a778fbe8f9485d7 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sun, 26 Jul 2020 13:42:09 +0000 Subject: [PATCH 204/427] =?UTF-8?q?bump:=20version=201.24.0=20=E2=86=92=20?= =?UTF-8?q?1.25.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 816c1033de..47cdc6baf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v1.25.0 (2020-07-26) + +### Feat + +- **conventional_commits**: use and proper support for conventional commits v1.0.0 + ## v1.24.0 (2020-07-26) ### Feat diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 4404cab319..d1067bcb69 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.24.0" +__version__ = "1.25.0" diff --git a/pyproject.toml b/pyproject.toml index e32016ee88..6936c60643 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.24.0" +version = "1.25.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.24.0" +version = "1.25.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 0317eaeac8c1afa1cf823cd050a51dd4fb10e30e Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 25 Jul 2020 21:32:28 +0800 Subject: [PATCH 205/427] fix(cli): make command required for commitizen BREAKING CHANGE: "cz --debug" will no longer work #47 --- commitizen/cli.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index bcba5cf86d..a4d59a5508 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -32,8 +32,7 @@ ], "subcommands": { "title": "commands", - # TODO: Add this constraint back in 2.0 - # "required": True, + "required": True, "commands": [ { "name": ["init"], @@ -292,12 +291,7 @@ def main(): logging.getLogger("commitizen").setLevel(logging.DEBUG) sys.excepthook = commitizen_debug_excepthook - # TODO: This try block can be removed after command is required in 2.0 - # Handle the case that argument is given, but no command is provided - try: - args.func(conf, vars(args))() - except AttributeError: - raise NoCommandFoundError() + args.func(conf, vars(args))() if __name__ == "__main__": From b4508a9161b10999576869a0e1cc20746b39f147 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 25 Jul 2020 21:47:04 +0800 Subject: [PATCH 206/427] refactor(cli): remove "--version" argument BREAKING CHANGE: Use "cz verion" instead --- commitizen/cli.py | 16 ---------------- tests/test_cli.py | 15 --------------- 2 files changed, 31 deletions(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index a4d59a5508..e25c3e1a77 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -1,7 +1,6 @@ import argparse import logging import sys -import warnings from functools import partial from decli import cli @@ -24,11 +23,6 @@ "name": ["-n", "--name"], "help": "use the given commitizen (default: cz_conventional_commits)", }, - { - "name": ["--version"], - "action": "store_true", - "help": "get the version of the installed commitizen", - }, ], "subcommands": { "title": "commands", @@ -277,16 +271,6 @@ def main(): elif not args.name and not conf.path: conf.update({"name": "cz_conventional_commits"}) - if args.version: - warnings.warn( - ( - "'cz --version' will be deprecated in next major version. " - "Please use 'cz version' command from your scripts" - ), - category=DeprecationWarning, - ) - args.func = commands.Version - if args.debug: logging.getLogger("commitizen").setLevel(logging.DEBUG) sys.excepthook = commitizen_debug_excepthook diff --git a/tests/test_cli.py b/tests/test_cli.py index a2fb7b8077..a21d839a86 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -55,21 +55,6 @@ def test_ls(mocker, capsys): assert isinstance(out, str) -def test_arg_version(mocker, capsys): - testargs = ["cz", "--version"] - mocker.patch.object(sys, "argv", testargs) - - with pytest.warns(DeprecationWarning) as record: - cli.main() - out, _ = capsys.readouterr() - assert out.strip() == __version__ - - assert record[0].message.args[0] == ( - "'cz --version' will be deprecated in next major version. " - "Please use 'cz version' command from your scripts" - ) - - def test_arg_debug(mocker): testargs = ["cz", "--debug", "info"] mocker.patch.object(sys, "argv", testargs) From a8417ed2c7915a51bf3a588693caf14a108d42a2 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 25 Jul 2020 22:25:35 +0800 Subject: [PATCH 207/427] refactor(config): remove ini configuration support BREAKING CHANGE: setup.cfg, .cz and .cz.cfg are no longer supported --- commitizen/commands/init.py | 8 ++-- commitizen/config/__init__.py | 35 +-------------- commitizen/config/ini_config.py | 76 --------------------------------- commitizen/defaults.py | 7 +-- docs/bump.md | 25 ----------- docs/config.md | 35 +-------------- tests/test_cli.py | 1 - tests/test_conf.py | 43 ------------------- 8 files changed, 7 insertions(+), 223 deletions(-) delete mode 100644 commitizen/config/ini_config.py diff --git a/commitizen/commands/init.py b/commitizen/commands/init.py index 9310de254d..2d5a6a8e01 100644 --- a/commitizen/commands/init.py +++ b/commitizen/commands/init.py @@ -2,9 +2,9 @@ from packaging.version import Version from commitizen import factory, out -from commitizen.config import BaseConfig, IniConfig, TomlConfig +from commitizen.config import BaseConfig, TomlConfig from commitizen.cz import registry -from commitizen.defaults import long_term_support_config_files +from commitizen.defaults import config_files from commitizen.exceptions import NoAnswersError from commitizen.git import get_latest_tag_name, get_tag_names @@ -23,8 +23,6 @@ def __call__(self): if "toml" in config_path: self.config = TomlConfig(data="", path=config_path) - else: - self.config = IniConfig(data="", path=config_path) self.config.init_empty_config_content() @@ -43,7 +41,7 @@ def __call__(self): def _ask_config_path(self) -> str: name = questionary.select( "Please choose a supported config file: (default: pyproject.toml)", - choices=long_term_support_config_files, + choices=config_files, default="pyproject.toml", style=self.cz.style, ).ask() diff --git a/commitizen/config/__init__.py b/commitizen/config/__init__.py index 04c39f3dd4..cf7af9311b 100644 --- a/commitizen/config/__init__.py +++ b/commitizen/config/__init__.py @@ -1,37 +1,11 @@ -import warnings from pathlib import Path -from typing import Optional, Union from commitizen import defaults, git from .base_config import BaseConfig -from .ini_config import IniConfig from .toml_config import TomlConfig -def load_global_conf() -> Optional[IniConfig]: - home = Path.home() - global_cfg = home / Path(".cz") - if not global_cfg.exists(): - return None - - # global conf doesn't make sense with commitizen bump - # so I'm deprecating it and won't test it - message = ( - "Global conf will be deprecated in next major version. " - "Use per project configuration. " - "Remove '~/.cz' file from your conf folder." - ) - warnings.simplefilter("always", DeprecationWarning) - warnings.warn(message, category=DeprecationWarning) - - with open(global_cfg, "r") as f: - data = f.read() - - conf = IniConfig(data=data, path=global_cfg) - return conf - - def read_cfg() -> BaseConfig: conf = BaseConfig() @@ -52,11 +26,9 @@ def read_cfg() -> BaseConfig: with open(filename, "r") as f: data: str = f.read() - _conf: Union[TomlConfig, IniConfig] + _conf: TomlConfig if "toml" in filename.suffix: _conf = TomlConfig(data=data, path=filename) - else: - _conf = IniConfig(data=data, path=filename) if _conf.is_empty_config: continue @@ -64,9 +36,4 @@ def read_cfg() -> BaseConfig: conf = _conf break - if not conf.path: - global_conf = load_global_conf() - if global_conf: - conf = global_conf - return conf diff --git a/commitizen/config/ini_config.py b/commitizen/config/ini_config.py deleted file mode 100644 index 78274123db..0000000000 --- a/commitizen/config/ini_config.py +++ /dev/null @@ -1,76 +0,0 @@ -import configparser -import json -import warnings -from pathlib import Path -from typing import Union - -from .base_config import BaseConfig - - -class IniConfig(BaseConfig): - def __init__(self, *, data: str, path: Union[Path, str]): - super(IniConfig, self).__init__() - self.is_empty_config = False - self._parse_setting(data) - self.add_path(path) - - def init_empty_config_file(self): - with open(self.path, "w") as toml_file: - toml_file.write("[commitizen]") - - def set_key(self, key, value): - """Set or update a key in the conf. - - For now only strings are supported. - We use to update the version number. - """ - parser = configparser.ConfigParser() - parser.read(self.path) - parser["commitizen"][key] = value - with open(self.path, "w") as f: - parser.write(f) - return self - - def _parse_setting(self, data: str): - """We expect to have a section like this - - ``` - [commitizen] - name = cz_jira - version_files = [ - "commitizen/__version__.py", - "pyproject.toml" - ] # this tab at the end is important - style = [ - ["pointer", "reverse"], - ["question", "underline"] - ] # this tab at the end is important - ``` - """ - config = configparser.ConfigParser(allow_no_value=True) - config.read_string(data) - try: - _data: dict = dict(config["commitizen"]) - if "files" in _data: - IniConfig._show_files_column_deprecated_warning() - _data.update({"version_files": json.loads(_data["files"])}) - - if "version_files" in _data: - _data.update({"version_files": json.loads(_data["version_files"])}) - - if "style" in _data: - _data.update({"style": json.loads(_data["style"])}) - - self._settings.update(_data) - except KeyError: - self.is_empty_config = True - else: - warnings.simplefilter("always", DeprecationWarning) - warnings.warn( - ( - ".cz, setup.cfg, and .cz.cfg will be deprecated " - "in next major version. \n" - 'Please use "pyproject.toml", ".cz.toml" instead' - ), - category=DeprecationWarning, - ) diff --git a/commitizen/defaults.py b/commitizen/defaults.py index 1f4adf52e6..8c871840ed 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -1,11 +1,8 @@ from collections import OrderedDict -from typing import Any, Dict +from typing import Any, Dict, List name: str = "cz_conventional_commits" -# TODO: .cz, setup.cfg, .cz.cfg should be removed in 2.0 -long_term_support_config_files: list = ["pyproject.toml", ".cz.toml"] -deprcated_config_files: list = [".cz", "setup.cfg", ".cz.cfg"] -config_files: list = long_term_support_config_files + deprcated_config_files +config_files: List[str] = ["pyproject.toml", ".cz.toml"] DEFAULT_SETTINGS: Dict[str, Any] = { "name": "cz_conventional_commits", diff --git a/docs/bump.md b/docs/bump.md index d09e3e1931..6fb3618b8e 100644 --- a/docs/bump.md +++ b/docs/bump.md @@ -131,7 +131,6 @@ However, it will still update `pyproject.toml` and `src/__version__.py`. To fix it, you'll first `git checkout .` to reset to the status before trying to bump and update the version in `setup.py` to `1.21.0` - ## Configuration ### `tag_format` @@ -155,13 +154,6 @@ In your `pyproject.toml` or `.cz.toml` tag_format = "v$minor.$major.$patch$prerelease" ``` -Or in your `.cz` (TO BE DEPRECATED) - -```ini -[commitizen] -tag_format = v$minor.$major.$patch$prerelease -``` - The variables must be preceded by a `$` sign. Supported variables: @@ -198,16 +190,6 @@ version_files = [ ] ``` -`.cz` (TO BE DEPRECATED) - -```ini -[commitizen] -version_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 in a line containing the `version` substring. @@ -234,13 +216,6 @@ Some examples bump_message = "release $current_version → $new_version [skip-ci]" ``` -`.cz` (TO BE DEPRECATED) - -```ini -[commitizen] -bump_message = release $current_version → $new_version [skip-ci] -``` - ## Custom bump Read the [customizing section](./customization.md). diff --git a/docs/config.md b/docs/config.md index a34292975e..b27fda0ce6 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1,7 +1,5 @@ # Configuration -Commitizen has support for `toml` and `ini` files. It first looks up the configuration file in the current working directory and then the root directory of the git project. - ## pyproject.toml or .cz.toml Add an entry to `pyproject.toml` or `.cz.toml`. Recommended for **python** projects. @@ -28,38 +26,7 @@ style = [ ] ``` -## INI files - -**INI files will not be supported in the next major version. Please use toml instead** - -Supported files: `.cz`, `.cz.cfg`, `setup.cfg`, and `$HOME/.cz` - -The format is slightly different to the `toml`, so pay attention. -Recommended for **other languages** projects (js, go, etc). - -```ini -[commitizen] -name = cz_conventional_commits -version = 0.1.0 -version_files = [ - "src/__version__.py", - "pyproject.toml:version" - ] -style = [ - ["qmark", "fg:#ff9d00 bold"], - ["question", "bold"], - ["answer", "fg:#ff9d00 bold"], - ["pointer", "fg:#ff9d00 bold"], - ["highlighted", "fg:#ff9d00 bold"], - ["selected", "fg:#cc5454"], - ["separator", "fg:#cc5454"], - ["instruction", ""], - ["text", ""], - ["disabled", "fg:#858585 italic"] - ] -``` - -The extra tab before the square brackets (`]`) at the end is required. +`.cz.toml` is recommended for **other languages** projects (js, go, etc). ## Settings diff --git a/tests/test_cli.py b/tests/test_cli.py index a21d839a86..7935806be2 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -3,7 +3,6 @@ import pytest from commitizen import cli -from commitizen.__version__ import __version__ from commitizen.exceptions import ExpectedExit, NoCommandFoundError, NotAGitProjectError diff --git a/tests/test_conf.py b/tests/test_conf.py index fd9bd66c77..0a4760e64e 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -23,19 +23,6 @@ target-version = ['py36', 'py37', 'py38'] """ -RAW_CONFIG = """ -[commitizen] -name = cz_jira -version = 1.0.0 -version_files = [ - "commitizen/__version__.py", - "pyproject.toml" - ] -style = [ - ["pointer", "reverse"], - ["question", "underline"] - ] -""" _settings = { "name": "cz_jira", @@ -83,8 +70,6 @@ def config_files_manager(request): with open(filepath, "w") as f: if "toml" in filename: f.write(PYPROJECT) - else: - f.write(RAW_CONFIG) yield os.remove(filepath) @@ -92,24 +77,10 @@ def config_files_manager(request): @pytest.fixture def empty_pyproject_ok_cz(): pyproject = "tests/pyproject.toml" - cz = "tests/.cz" with open(pyproject, "w") as f: f.write("") - with open(cz, "w") as f: - f.write(RAW_CONFIG) yield os.remove(pyproject) - os.remove(cz) - - -def test_load_global_conf(mocker, tmpdir): - with tmpdir.as_cwd(): - config_file = tmpdir.join(".cz") - config_file.write(RAW_CONFIG) - - mocked_path = mocker.patch("commitizen.config.Path", return_value=Path(".cz")) - mocked_path.home.return_value = Path(tmpdir) - print(config.load_global_conf()) @pytest.mark.parametrize( @@ -120,13 +91,6 @@ def test_load_conf(config_files_manager, configure_supported_files): assert cfg.settings == _settings -def test_conf_is_loaded_with_empty_pyproject_but_ok_cz( - empty_pyproject_ok_cz, configure_supported_files -): - cfg = config.read_cfg() - assert cfg.settings == _settings - - def test_conf_returns_default_when_no_files(configure_supported_files): cfg = config.read_cfg() assert cfg.settings == defaults.DEFAULT_SETTINGS @@ -149,13 +113,6 @@ def test_find_git_project_root(tmpdir): assert git.find_git_project_root() is None -class TestInilConfig: - def test_read_setup_cfg_without_commitizen_config(self, tmpdir): - path = tmpdir.mkdir("commitizen").join("setup.cfg") - ini_config = config.IniConfig(data="", path=path) - assert ini_config.is_empty_config - - class TestTomlConfig: def test_init_empty_config_content(self, tmpdir): path = tmpdir.mkdir("commitizen").join(".cz.toml") From 4d36bdf01823f62d5dd8cb4a942f9a396c0e7208 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 25 Jul 2020 22:41:05 +0800 Subject: [PATCH 208/427] refactor(config): drop "files" configure support. Please use "version_files" instead BREAKING CHANGE: #82 --- commitizen/config/base_config.py | 14 -------------- commitizen/config/toml_config.py | 4 ---- 2 files changed, 18 deletions(-) diff --git a/commitizen/config/base_config.py b/commitizen/config/base_config.py index f5febf3d34..f3e0767dd2 100644 --- a/commitizen/config/base_config.py +++ b/commitizen/config/base_config.py @@ -1,4 +1,3 @@ -import warnings from pathlib import Path from typing import Any, Dict, Optional, Union @@ -34,16 +33,3 @@ def add_path(self, path: Union[str, Path]): def _parse_setting(self, data: str) -> dict: raise NotImplementedError() - - # TODO: remove "files" supported in 2.0 - @classmethod - def _show_files_column_deprecated_warning(cls): - warnings.simplefilter("always", DeprecationWarning) - warnings.warn( - ( - '"files" is renamed as "version_files" ' - "and will be deprecated in next major version\n" - 'Please repalce "files" with "version_files"' - ), - category=DeprecationWarning, - ) diff --git a/commitizen/config/toml_config.py b/commitizen/config/toml_config.py index e13d720a17..a9b3cfab1e 100644 --- a/commitizen/config/toml_config.py +++ b/commitizen/config/toml_config.py @@ -44,7 +44,3 @@ def _parse_setting(self, data: str): self.settings.update(doc["tool"]["commitizen"]) except exceptions.NonExistentKey: self.is_empty_config = True - - if "files" in self.settings: - self.settings["version_files"] = self.settings["files"] - TomlConfig._show_files_column_deprecated_warning From 7638381f22c279bcfeab10ee17bef7aa470c9e98 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 26 Jul 2020 16:46:16 +0800 Subject: [PATCH 209/427] build(poetry): lock decli to > 0.5.2 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 6936c60643..2200f31650 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,7 +46,7 @@ classifiers = [ [tool.poetry.dependencies] python = "^3.6.1" questionary = "^1.4.0" -decli = "^0.5.0" +decli = "^0.5.2" colorama = "^0.4.1" termcolor = "^1.1" packaging = ">=19,<21" From 0df4fb175eff4dea52387834f28c28c97fba63a2 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 26 Jul 2020 17:33:50 +0800 Subject: [PATCH 210/427] test(conf): add test case that empty pyproject and .cz.toml both exist --- tests/test_conf.py | 77 ++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 43 deletions(-) diff --git a/tests/test_conf.py b/tests/test_conf.py index 0a4760e64e..241f2117d5 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -54,63 +54,54 @@ @pytest.fixture -def configure_supported_files(): - original = defaults.config_files.copy() +def config_files_manager(request, tmpdir): + with tmpdir.as_cwd(): + filename = request.param + with open(filename, "w") as f: + if "toml" in filename: + f.write(PYPROJECT) + yield - # patch the defaults to include tests - defaults.config_files = [os.path.join("tests", f) for f in defaults.config_files] - yield - defaults.config_files = original - - -@pytest.fixture -def config_files_manager(request): - filename = request.param - filepath = os.path.join("tests", filename) - with open(filepath, "w") as f: - if "toml" in filename: - f.write(PYPROJECT) - yield - os.remove(filepath) - - -@pytest.fixture -def empty_pyproject_ok_cz(): - pyproject = "tests/pyproject.toml" - with open(pyproject, "w") as f: - f.write("") - yield - os.remove(pyproject) - - -@pytest.mark.parametrize( - "config_files_manager", defaults.config_files.copy(), indirect=True -) -def test_load_conf(config_files_manager, configure_supported_files): - cfg = config.read_cfg() - assert cfg.settings == _settings +def test_find_git_project_root(tmpdir): + assert git.find_git_project_root() == Path(os.getcwd()) -def test_conf_returns_default_when_no_files(configure_supported_files): - cfg = config.read_cfg() - assert cfg.settings == defaults.DEFAULT_SETTINGS + with tmpdir.as_cwd() as _: + assert git.find_git_project_root() is None @pytest.mark.parametrize( "config_files_manager", defaults.config_files.copy(), indirect=True ) -def test_set_key(configure_supported_files, config_files_manager): +def test_set_key(config_files_manager): _conf = config.read_cfg() _conf.set_key("version", "2.0.0") cfg = config.read_cfg() assert cfg.settings == _new_settings -def test_find_git_project_root(tmpdir): - assert git.find_git_project_root() == Path(os.getcwd()) - - with tmpdir.as_cwd() as _: - assert git.find_git_project_root() is None +class TestReadCfg: + @pytest.mark.parametrize( + "config_files_manager", defaults.config_files.copy(), indirect=True + ) + def test_load_conf(_, config_files_manager): + cfg = config.read_cfg() + assert cfg.settings == _settings + + def test_conf_returns_default_when_no_files(_, tmpdir): + with tmpdir.as_cwd(): + cfg = config.read_cfg() + assert cfg.settings == defaults.DEFAULT_SETTINGS + + def test_load_empty_pyproject_toml_and_cz_toml_with_config(_, tmpdir): + with tmpdir.as_cwd(): + p = tmpdir.join("pyproject.toml") + p.write("") + p = tmpdir.join(".cz.toml") + p.write(PYPROJECT) + + cfg = config.read_cfg() + assert cfg.settings == _settings class TestTomlConfig: From 13a6dd0e5423ffd4150f3c93800f74ea3f32a8a9 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 26 Jul 2020 17:36:41 +0800 Subject: [PATCH 211/427] docs(init): remove unneeded TODO (the feature has been implemented) --- commitizen/commands/init.py | 1 - 1 file changed, 1 deletion(-) diff --git a/commitizen/commands/init.py b/commitizen/commands/init.py index 2d5a6a8e01..aa36b6c180 100644 --- a/commitizen/commands/init.py +++ b/commitizen/commands/init.py @@ -35,7 +35,6 @@ def __call__(self): out.info("cz bump --changelog") out.success("The configuration are all set.") else: - # TODO: handle the case that config file exist but no value out.line(f"Config file {self.config.path} already exists") def _ask_config_path(self) -> str: From c619c87483e88e18205f94bfd5e017f2b296fac9 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 26 Jul 2020 23:25:02 +0800 Subject: [PATCH 212/427] feat(init): enable setting up pre-commit hook through "cz init" --- commitizen/commands/init.py | 55 ++++++++++++- tests/commands/test_init_command.py | 117 +++++++++++++++++++++++++--- tests/test_git.py | 8 +- tests/utils.py | 7 ++ 4 files changed, 168 insertions(+), 19 deletions(-) diff --git a/commitizen/commands/init.py b/commitizen/commands/init.py index aa36b6c180..1c459d5ed4 100644 --- a/commitizen/commands/init.py +++ b/commitizen/commands/init.py @@ -1,7 +1,11 @@ +import os + import questionary +import yaml from packaging.version import Version -from commitizen import factory, out +from commitizen import cmd, factory, out +from commitizen.__version__ import __version__ from commitizen.config import BaseConfig, TomlConfig from commitizen.cz import registry from commitizen.defaults import config_files @@ -20,7 +24,6 @@ def __call__(self): # No config for commitizen exist if not self.config.path: config_path = self._ask_config_path() - if "toml" in config_path: self.config = TomlConfig(data="", path=config_path) @@ -31,6 +34,10 @@ def __call__(self): values_to_add["version"] = Version(tag).public values_to_add["tag_format"] = self._ask_tag_format(tag) self._update_config_file(values_to_add) + + if questionary.confirm("Do you want to install pre-commit hook?").ask(): + self._install_pre_commit_hook() + out.write("You can bump the version and create changelog running:\n") out.info("cz bump --changelog") out.success("The configuration are all set.") @@ -98,6 +105,50 @@ def _ask_tag_format(self, latest_tag) -> str: tag_format = "$version" return tag_format + def _install_pre_commit_hook(self): + pre_commit_config_filename = ".pre-commit-config.yaml" + cz_hook_config = { + "repo": "https://github.com/commitizen-tools/commitizen", + "rev": f"v{__version__}", + "hooks": [{"id": "commitizen", "stages": ["commit-msg"]}], + } + + config_data = {} + if not os.path.isfile(pre_commit_config_filename): + # .pre-commit-config does not exist + config_data["repos"] = [cz_hook_config] + else: + # breakpoint() + with open(pre_commit_config_filename) as config_file: + yaml_data = yaml.safe_load(config_file) + if yaml_data: + config_data = yaml_data + + if "repos" in config_data: + for pre_commit_hook in config_data["repos"]: + if "commitizen" in pre_commit_hook["repo"]: + out.write("commitizen already in pre-commit config") + break + else: + config_data["repos"].append(cz_hook_config) + else: + # .pre-commit-config exists but there's no "repos" key + config_data["repos"] = [cz_hook_config] + + with open(pre_commit_config_filename, "w") as config_file: + yaml.safe_dump(config_data, stream=config_file) + + c = cmd.run("pre-commit install --hook-type commit-msg") + if c.return_code == 127: + out.error( + "pre-commit is not installed in current environement.\n" + "Run 'pre-commit install --hook-type commit-msg' again after it's installed" + ) + elif c.return_code != 0: + out.error(c.err) + else: + out.write("commitizen pre-commit hook is now installed in your '.git'\n") + def _update_config_file(self, values): for key, value in values.items(): self.config.set_key(key, value) diff --git a/tests/commands/test_init_command.py b/tests/commands/test_init_command.py index 39a0794005..555e0d816c 100644 --- a/tests/commands/test_init_command.py +++ b/tests/commands/test_init_command.py @@ -1,6 +1,10 @@ +import os + import pytest +import yaml from commitizen import commands +from commitizen.__version__ import __version__ from commitizen.exceptions import NoAnswersError @@ -12,7 +16,22 @@ def ask(self): return self.expected_return -def test_init(tmpdir, mocker, config): +pre_commit_config_filename = ".pre-commit-config.yaml" +cz_hook_config = { + "repo": "https://github.com/commitizen-tools/commitizen", + "rev": f"v{__version__}", + "hooks": [{"id": "commitizen", "stages": ["commit-msg"]}], +} + +expected_config = ( + "[tool.commitizen]\n" + 'name = "cz_conventional_commits"\n' + 'version = "0.0.1"\n' + 'tag_format = "$version"\n' +) + + +def test_init_without_setup_pre_commit_hook(tmpdir, mocker, config): mocker.patch( "questionary.select", side_effect=[ @@ -20,23 +39,19 @@ def test_init(tmpdir, mocker, config): FakeQuestion("cz_conventional_commits"), ], ) - mocker.patch("questionary.confirm", return_value=FakeQuestion("y")) - mocker.patch("questionary.text", return_value=FakeQuestion("y")) - expected_config = ( - "[tool.commitizen]\n" - 'name = "cz_conventional_commits"\n' - 'version = "0.0.1"\n' - 'tag_format = "y"\n' - ) + mocker.patch("questionary.confirm", return_value=FakeQuestion(True)) + mocker.patch("questionary.text", return_value=FakeQuestion("$version")) + mocker.patch("questionary.confirm", return_value=FakeQuestion(False)) with tmpdir.as_cwd(): commands.Init(config)() with open("pyproject.toml", "r") as toml_file: config_data = toml_file.read() - assert config_data == expected_config + assert not os.path.isfile(pre_commit_config_filename) + def test_init_when_config_already_exists(config, capsys): # Set config path @@ -67,3 +82,85 @@ def test_init_without_choosing_tag(config, mocker, tmpdir): with tmpdir.as_cwd(): with pytest.raises(NoAnswersError): commands.Init(config)() + + +class TestPreCommitCases: + @pytest.fixture(scope="function", autouse=True) + def default_choices(_, mocker): + mocker.patch( + "questionary.select", + side_effect=[ + FakeQuestion("pyproject.toml"), + FakeQuestion("cz_conventional_commits"), + ], + ) + mocker.patch("questionary.confirm", return_value=FakeQuestion(True)) + mocker.patch("questionary.text", return_value=FakeQuestion("$version")) + mocker.patch("questionary.confirm", return_value=FakeQuestion(True)) + + def test_no_existing_pre_commit_conifg(_, tmpdir, config): + with tmpdir.as_cwd(): + commands.Init(config)() + + with open("pyproject.toml", "r") as toml_file: + config_data = toml_file.read() + assert config_data == expected_config + + with open(pre_commit_config_filename, "r") as pre_commit_file: + pre_commit_config_data = yaml.safe_load(pre_commit_file.read()) + assert pre_commit_config_data == {"repos": [cz_hook_config]} + + def test_empty_pre_commit_config(_, tmpdir, config): + with tmpdir.as_cwd(): + p = tmpdir.join(pre_commit_config_filename) + p.write("") + + commands.Init(config)() + + with open("pyproject.toml", "r") as toml_file: + config_data = toml_file.read() + assert config_data == expected_config + + with open(pre_commit_config_filename, "r") as pre_commit_file: + pre_commit_config_data = yaml.safe_load(pre_commit_file.read()) + assert pre_commit_config_data == {"repos": [cz_hook_config]} + + def test_pre_commit_config_without_cz_hook(_, tmpdir, config): + existing_hook_config = { + "repo": "https://github.com/pre-commit/pre-commit-hooks", + "rev": "v1.2.3", + "hooks": [{"id", "trailing-whitespace"}], + } + + with tmpdir.as_cwd(): + p = tmpdir.join(pre_commit_config_filename) + p.write(yaml.safe_dump({"repos": [existing_hook_config]})) + + commands.Init(config)() + + with open("pyproject.toml", "r") as toml_file: + config_data = toml_file.read() + assert config_data == expected_config + + with open(pre_commit_config_filename, "r") as pre_commit_file: + pre_commit_config_data = yaml.safe_load(pre_commit_file.read()) + assert pre_commit_config_data == { + "repos": [existing_hook_config, cz_hook_config] + } + + def test_cz_hook_exists_in_pre_commit_config(_, tmpdir, config): + with tmpdir.as_cwd(): + p = tmpdir.join(pre_commit_config_filename) + p.write(yaml.safe_dump({"repos": [cz_hook_config]})) + + commands.Init(config)() + + with open("pyproject.toml", "r") as toml_file: + config_data = toml_file.read() + assert config_data == expected_config + + with open(pre_commit_config_filename, "r") as pre_commit_file: + pre_commit_config_data = yaml.safe_load(pre_commit_file.read()) + + # check that config is not duplicated + assert pre_commit_config_data == {"repos": [cz_hook_config]} diff --git a/tests/test_git.py b/tests/test_git.py index 0fa22df12e..92abc2f040 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -1,13 +1,7 @@ import pytest from commitizen import git -from tests.utils import create_file_and_commit - - -class FakeCommand: - def __init__(self, out=None, err=None): - self.out = out - self.err = err +from tests.utils import FakeCommand, create_file_and_commit def test_git_object_eq(): diff --git a/tests/utils.py b/tests/utils.py index 64598b8df1..7f5b2b87f3 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -5,6 +5,13 @@ from commitizen import cmd, git +class FakeCommand: + def __init__(self, out=None, err=None, return_code=0): + self.out = out + self.err = err + self.return_code = return_code + + def create_file_and_commit(message: str, filename: Optional[str] = None): if not filename: filename = str(uuid.uuid4()) From 3785146c3aa4e52d757fca1a9f75fd0ec61ed5cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sun, 26 Jul 2020 17:55:56 +0200 Subject: [PATCH 213/427] fix: add missing `pyyaml` dependency --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 2200f31650..0ad3abb46a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,6 +52,7 @@ termcolor = "^1.1" packaging = ">=19,<21" tomlkit = "^0.5.3" jinja2 = "^2.10.3" +pyyaml = ">=3.08" [tool.poetry.dev-dependencies] ipython = "^7.2" From e24530e45914d85d135c82adb7c5f4618c53d04f Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sun, 26 Jul 2020 16:16:49 +0000 Subject: [PATCH 214/427] =?UTF-8?q?bump:=20version=201.25.0=20=E2=86=92=20?= =?UTF-8?q?2.0.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 23 +++++++++++++++++++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47cdc6baf9..617a48dc9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,26 @@ +## v2.0.0 (2020-07-26) + +### Fix + +- add missing `pyyaml` dependency +- **cli**: make command required for commitizen + +### Feat + +- **init**: enable setting up pre-commit hook through "cz init" + +### Refactor + +- **config**: drop "files" configure support. Please use "version_files" instead +- **config**: remove ini configuration support +- **cli**: remove "--version" argument + +### BREAKING CHANGE + +- setup.cfg, .cz and .cz.cfg are no longer supported +- Use "cz verion" instead +- "cz --debug" will no longer work + ## v1.25.0 (2020-07-26) ### Feat diff --git a/commitizen/__version__.py b/commitizen/__version__.py index d1067bcb69..8c0d5d5bb2 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "1.25.0" +__version__ = "2.0.0" diff --git a/pyproject.toml b/pyproject.toml index 0ad3abb46a..94268688d6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "1.25.0" +version = "2.0.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "1.25.0" +version = "2.0.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 57859c003462269116764d54a9af3081d36a5caf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 1 Aug 2020 17:42:19 +0200 Subject: [PATCH 215/427] fix(commands/bump): display message variable properly --- commitizen/commands/bump.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 43f0cba28b..36ea7e2524 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -123,7 +123,7 @@ def __call__(self): # noqa: C901 # Report found information out.write( - f"message\n" + f"{message}\n" f"tag to create: {new_tag_version}\n" f"increment detected: {increment}\n" ) From 509e74757ad74b60c9c98b01bd2f339f62d0ad08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 1 Aug 2020 18:02:39 +0200 Subject: [PATCH 216/427] fix(commands/changelog): add exception message when failing to find an incremental revision --- commitizen/exceptions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/commitizen/exceptions.py b/commitizen/exceptions.py index 8610a6fa74..9a63002c6a 100644 --- a/commitizen/exceptions.py +++ b/commitizen/exceptions.py @@ -123,6 +123,7 @@ class InvalidCommitMessageError(CommitizenException): class NoRevisionError(CommitizenException): exit_code = ExitCode.NO_REVISION + message = "No tag found to do an incremental changelog" class NoCommandFoundError(CommitizenException): From d6e6eb5f8509033811a8c7e86ad1eadcf012bf9e Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sun, 2 Aug 2020 03:17:45 +0000 Subject: [PATCH 217/427] =?UTF-8?q?bump:=20version=202.0.0=20=E2=86=92=202?= =?UTF-8?q?.0.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 7 +++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 617a48dc9c..8182fc2aa9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## v2.0.1 (2020-08-02) + +### Fix + +- **commands/changelog**: add exception message when failing to find an incremental revision +- **commands/bump**: display message variable properly + ## v2.0.0 (2020-07-26) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 8c0d5d5bb2..159d48b876 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.0.0" +__version__ = "2.0.1" diff --git a/pyproject.toml b/pyproject.toml index 94268688d6..c26416bea5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.0.0" +version = "2.0.1" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.0.0" +version = "2.0.1" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From c7f80eee726a6a016434810d7e27dfd23adc86a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Mon, 3 Aug 2020 08:48:11 +0200 Subject: [PATCH 218/427] docs: simplify pull request template --- .github/pull_request_template.md | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index cfeab88e69..d0d5eba17c 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -3,21 +3,10 @@ Thanks for sending a pull request! Please fill in the following content to let us know better about this change. --> -## Types of changes - -<!-- Please put an `x` in the box that applies --> - -- [ ] **Bug fix** -- [ ] **New feature** -- [ ] **Refactoring** -- [ ] **Breaking change** (any change that would cause existing functionality to not work as expected) -- [ ] **Documentation update** -- [ ] **Other (please describe)** - ## Description - <!-- Describe what the change is --> + ## Checklist - [ ] Add test cases to all the changes you introduce @@ -25,21 +14,16 @@ Please fill in the following content to let us know better about this change. - [ ] Test the changes on the local machine manually - [ ] Update the documentation for the changes -## Steps to Test This Pull Request +## Expected behavior +<!-- A clear and concise description of what you expected to happen --> + +## Steps to Test This Pull Request <!-- Steps to reproduce the behavior: 1. ... 2. ... 3. ... --> -## Expected behavior - -<!-- A clear and concise description of what you expected to happen --> - -## Related Issue - -<!-- If applicable, reference to the issue related to this pull request. --> ## Additional context - -<!-- Add any other context or screenshots about the pull request here. --> +<!-- Add any other RELATED ISSUE, context or screenshots about the pull request here. --> From 1fc35b009ee7f06e0ee74a43ab91f4926ffc7f76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Mon, 3 Aug 2020 08:41:50 +0200 Subject: [PATCH 219/427] fix(git): use double quotation mark in get_tags this bug affects windows users, by adding a single quotation in front of the tag --- commitizen/git.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commitizen/git.py b/commitizen/git.py index 66b902950f..81aa9166cf 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -99,9 +99,9 @@ def get_commits( def get_tags(dateformat: str = "%Y-%m-%d") -> List[GitTag]: inner_delimiter = "---inner_delimiter---" formatter = ( - f"'%(refname:lstrip=2){inner_delimiter}" + f'"%(refname:lstrip=2){inner_delimiter}' f"%(objectname){inner_delimiter}" - f"%(committerdate:format:{dateformat})'" + f'%(committerdate:format:{dateformat})"' ) c = cmd.run(f"git tag --format={formatter} --sort=-committerdate") if c.err or not c.out: From 09cf7b31cac7e9ba22720fcbfa0506d6e0ffc55c Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Mon, 3 Aug 2020 06:54:49 +0000 Subject: [PATCH 220/427] =?UTF-8?q?bump:=20version=202.0.1=20=E2=86=92=202?= =?UTF-8?q?.0.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8182fc2aa9..d5df8d9bf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v2.0.2 (2020-08-03) + +### Fix + +- **git**: use double quotation mark in get_tags + ## v2.0.1 (2020-08-02) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 159d48b876..0309ae290b 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.0.1" +__version__ = "2.0.2" diff --git a/pyproject.toml b/pyproject.toml index c26416bea5..113288e975 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.0.1" +version = "2.0.2" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.0.1" +version = "2.0.2" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 94f8ae07dfc8b57a69fedbd7d4297aef2a79cea5 Mon Sep 17 00:00:00 2001 From: Josix <wilson8507@gmail.com> Date: Mon, 3 Aug 2020 16:15:56 +0800 Subject: [PATCH 221/427] feat(cz_check): Update to show all ill-formatted commits --- commitizen/commands/check.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py index 764beb5a03..2a574e7648 100644 --- a/commitizen/commands/check.py +++ b/commitizen/commands/check.py @@ -50,14 +50,17 @@ def __call__(self): raise NoCommitsFoundError(f"No commit found with range: '{self.rev_range}'") pattern = self.cz.schema_pattern() + ill_formated_commits = [] for commit_msg in commit_msgs: if not Check.validate_commit_message(commit_msg, pattern): - raise InvalidCommitMessageError( - "commit validation: failed!\n" - "please enter a commit message in the commitizen format.\n" - f"commit: {commit_msg}\n" - f"pattern: {pattern}" - ) + ill_formated_commits.append(f"commit: {commit_msg}\n") + if ill_formated_commits != []: + raise InvalidCommitMessageError( + "commit validation: failed!\n" + "please enter a commit message in the commitizen format.\n" + f"{''.join(ill_formated_commits)}\n" + f"pattern: {pattern}" + ) out.success("Commit validation: successful!") def _get_commit_messages(self): From 1dee41ef9e4ed476079e245c463fc399e9be69fc Mon Sep 17 00:00:00 2001 From: Josix <wilson8507@gmail.com> Date: Thu, 6 Aug 2020 02:50:13 +0800 Subject: [PATCH 222/427] feat(cz_check): Add rev to all displayed ill-formatted commits * Update _get_commit_messages to get_commits with rev and msg info --- commitizen/commands/check.py | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py index 2a574e7648..28f3a21e47 100644 --- a/commitizen/commands/check.py +++ b/commitizen/commands/check.py @@ -45,33 +45,43 @@ def __call__(self): Raises: InvalidCommitMessageError: if the commit provided not follows the conventional pattern """ - commit_msgs = self._get_commit_messages() - if not commit_msgs: + commits = self._get_commits() + if not commits: raise NoCommitsFoundError(f"No commit found with range: '{self.rev_range}'") pattern = self.cz.schema_pattern() - ill_formated_commits = [] - for commit_msg in commit_msgs: - if not Check.validate_commit_message(commit_msg, pattern): - ill_formated_commits.append(f"commit: {commit_msg}\n") - if ill_formated_commits != []: + ill_formated_commits = [ + commit + for commit in commits + if not Check.validate_commit_message(commit["msg"], pattern) + ] + displayed_msgs_content = "".join( + [ + f"commit {commit['rev'] or ''}: {commit['msg']}\n" + for commit in ill_formated_commits + ] + ) + if displayed_msgs_content: raise InvalidCommitMessageError( "commit validation: failed!\n" "please enter a commit message in the commitizen format.\n" - f"{''.join(ill_formated_commits)}\n" + f"{displayed_msgs_content}\n" f"pattern: {pattern}" ) out.success("Commit validation: successful!") - def _get_commit_messages(self): + def _get_commits(self): # Get commit message from file (--commit-msg-file) if self.commit_msg_file: with open(self.commit_msg_file, "r") as commit_file: commit_msg = commit_file.read() - return [commit_msg] + return [{"rev": None, "msg": commit_msg}] # Get commit messages from git log (--rev-range) - return [commit.message for commit in git.get_commits(end=self.rev_range)] + return [ + {"rev": commit.rev[:8], "msg": commit.message} + for commit in git.get_commits(end=self.rev_range) + ] @staticmethod def validate_commit_message(commit_msg: str, pattern: str) -> bool: From 039e0417c04ade82737423d2221f52fd9f6b2f7e Mon Sep 17 00:00:00 2001 From: Josix <wilson8507@gmail.com> Date: Thu, 6 Aug 2020 13:02:15 +0800 Subject: [PATCH 223/427] refactor(cz_check): Refactor _get_commits to return GitCommit instead of dict --- commitizen/commands/check.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py index 28f3a21e47..12667171b9 100644 --- a/commitizen/commands/check.py +++ b/commitizen/commands/check.py @@ -53,11 +53,11 @@ def __call__(self): ill_formated_commits = [ commit for commit in commits - if not Check.validate_commit_message(commit["msg"], pattern) + if not Check.validate_commit_message(commit.message, pattern) ] - displayed_msgs_content = "".join( + displayed_msgs_content = "\n".join( [ - f"commit {commit['rev'] or ''}: {commit['msg']}\n" + f"commit {commit.rev}: {commit.message}" for commit in ill_formated_commits ] ) @@ -74,14 +74,18 @@ def _get_commits(self): # Get commit message from file (--commit-msg-file) if self.commit_msg_file: with open(self.commit_msg_file, "r") as commit_file: - commit_msg = commit_file.read() - return [{"rev": None, "msg": commit_msg}] + commit_title = commit_file.readline() + commit_body = commit_file.read() + return [ + git.GitCommit( + rev="", + title=commit_title, + body=commit_body, + ) + ] # Get commit messages from git log (--rev-range) - return [ - {"rev": commit.rev[:8], "msg": commit.message} - for commit in git.get_commits(end=self.rev_range) - ] + return git.get_commits(end=self.rev_range) @staticmethod def validate_commit_message(commit_msg: str, pattern: str) -> bool: From 34fca28c0af6b82975c1641bf7d6d1be234ae52b Mon Sep 17 00:00:00 2001 From: Josix <wilson8507@gmail.com> Date: Thu, 6 Aug 2020 13:03:25 +0800 Subject: [PATCH 224/427] test(cz_check): Add a range of failed commits test --- tests/commands/test_check_command.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/commands/test_check_command.py b/tests/commands/test_check_command.py index 5ea824af33..47d1a94bb9 100644 --- a/tests/commands/test_check_command.py +++ b/tests/commands/test_check_command.py @@ -207,3 +207,25 @@ def test_check_command_with_empty_range(config, mocker): check_cmd() assert "No commit found with range: 'master..master'" in str(excinfo) + + +def test_check_a_range_of_failed_git_commits(config, mocker): + ill_formated_commits_msgs = [ + "First commit does not follow rule", + "Second commit does not follow rule", + ( + "Third commit does not follow rule\n" + "Ill-formatted commit with body" + ) + ] + mocker.patch( + "commitizen.git.get_commits", + return_value=_build_fake_git_commits(ill_formated_commits_msgs), + ) + check_cmd = commands.Check( + config=config, arguments={"rev_range": "HEAD~10..master"} + ) + + with pytest.raises(InvalidCommitMessageError) as excinfo: + check_cmd() + assert all([msg in str(excinfo.value) for msg in ill_formated_commits_msgs]) From ba16783e98870e76502378b3698d8e0a173e343d Mon Sep 17 00:00:00 2001 From: Josix <wilson8507@gmail.com> Date: Thu, 6 Aug 2020 13:07:44 +0800 Subject: [PATCH 225/427] style(cz_check): Update ill-formatted codes --- commitizen/commands/check.py | 8 +------- tests/commands/test_check_command.py | 11 ++++------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py index 12667171b9..b9c2f94ec8 100644 --- a/commitizen/commands/check.py +++ b/commitizen/commands/check.py @@ -76,13 +76,7 @@ def _get_commits(self): with open(self.commit_msg_file, "r") as commit_file: commit_title = commit_file.readline() commit_body = commit_file.read() - return [ - git.GitCommit( - rev="", - title=commit_title, - body=commit_body, - ) - ] + return [git.GitCommit(rev="", title=commit_title, body=commit_body)] # Get commit messages from git log (--rev-range) return git.get_commits(end=self.rev_range) diff --git a/tests/commands/test_check_command.py b/tests/commands/test_check_command.py index 47d1a94bb9..5973851e1c 100644 --- a/tests/commands/test_check_command.py +++ b/tests/commands/test_check_command.py @@ -211,13 +211,10 @@ def test_check_command_with_empty_range(config, mocker): def test_check_a_range_of_failed_git_commits(config, mocker): ill_formated_commits_msgs = [ - "First commit does not follow rule", - "Second commit does not follow rule", - ( - "Third commit does not follow rule\n" - "Ill-formatted commit with body" - ) - ] + "First commit does not follow rule", + "Second commit does not follow rule", + ("Third commit does not follow rule\n" "Ill-formatted commit with body"), + ] mocker.patch( "commitizen.git.get_commits", return_value=_build_fake_git_commits(ill_formated_commits_msgs), From 0d5086eed100d1dec184c497bc9c45d9d9e2a48c Mon Sep 17 00:00:00 2001 From: Josix <wilson8507@gmail.com> Date: Thu, 6 Aug 2020 14:22:32 +0800 Subject: [PATCH 226/427] style(cz_check): Add quote to displaying rev and msg --- commitizen/commands/check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py index b9c2f94ec8..6a2f8f400a 100644 --- a/commitizen/commands/check.py +++ b/commitizen/commands/check.py @@ -57,7 +57,7 @@ def __call__(self): ] displayed_msgs_content = "\n".join( [ - f"commit {commit.rev}: {commit.message}" + f'commit "{commit.rev}": "{commit.message}"' for commit in ill_formated_commits ] ) From debe2cede5b9515024c1184059c6aac811ea3adc Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 6 Aug 2020 06:38:35 +0000 Subject: [PATCH 227/427] =?UTF-8?q?bump:=20version=202.0.2=20=E2=86=92=202?= =?UTF-8?q?.1.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 11 +++++++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5df8d9bf0..77bd935d89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## v2.1.0 (2020-08-06) + +### Refactor + +- **cz_check**: Refactor _get_commits to return GitCommit instead of dict + +### Feat + +- **cz_check**: Add rev to all displayed ill-formatted commits +- **cz_check**: Update to show all ill-formatted commits + ## v2.0.2 (2020-08-03) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 0309ae290b..9aa3f90365 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.0.2" +__version__ = "2.1.0" diff --git a/pyproject.toml b/pyproject.toml index 113288e975..07d13d826d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.0.2" +version = "2.1.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.0.2" +version = "2.1.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 750213c7c6c25bdc619343b5d7ca159483830f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Thu, 6 Aug 2020 14:48:00 +0200 Subject: [PATCH 228/427] docs(README): fix link to documentation --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 189504fb3b..5bd9e0af85 100644 --- a/docs/README.md +++ b/docs/README.md @@ -11,7 +11,7 @@ versions](https://img.shields.io/pypi/pyversions/commitizen.svg?style=flat-squar --- -**Documentation**: https://commitizen-tools.github.io/ +**Documentation**: https://commitizen-tools.github.io/commitizen/ --- From 7ec5c1fbbb2d7e1b2cc86778cf111d56f3b1294b Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 30 Aug 2020 16:12:12 +0800 Subject: [PATCH 229/427] ci(github-action): use commitizen github action --- .github/workflows/bumpversion.yml | 39 +++++++------------------------ 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/.github/workflows/bumpversion.yml b/.github/workflows/bumpversion.yml index cd4698de67..1e9ce7da59 100644 --- a/.github/workflows/bumpversion.yml +++ b/.github/workflows/bumpversion.yml @@ -9,34 +9,13 @@ jobs: bump-version: if: "!startsWith(github.event.head_commit.message, 'bump:')" runs-on: ubuntu-latest - strategy: - matrix: - python-version: ['3.x'] + name: "Bump version and create changelog with commitizen" steps: - - uses: actions/checkout@v2 - with: - token: '${{ secrets.PERSONAL_ACCESS_TOKEN }}' - fetch-depth: 0 - - 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 -m pip install -U pip poetry - - name: Configure repo - run: | - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - git pull origin master --tags - poetry install --no-dev - - name: Create bump - run: | - poetry run cz bump --yes --changelog - git tag - - name: Push changes - uses: Woile/github-push-action@master - with: - github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} - tags: "true" + - name: Check out + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Create bump and changelog + uses: commitizen-tools/commitizen-action@master + with: + github_token: ${{ secrets.GITHUB_TOKEN }} From 01520eb2684332797771a936e8f5b8d0fc76bf23 Mon Sep 17 00:00:00 2001 From: Jordan Su <newjordansu1126@gmail.com> Date: Mon, 31 Aug 2020 01:42:30 +0800 Subject: [PATCH 230/427] feat(cz_check): cz check can read from a string input --- commitizen/cli.py | 5 +++++ commitizen/commands/check.py | 7 ++++++- tests/commands/test_check_command.py | 19 +++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index e25c3e1a77..d09ba76d20 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -195,6 +195,11 @@ "help": "a range of git rev to check. e.g, master..HEAD", "exclusive_group": "group1", }, + { + "name": ["-m", "--message"], + "help": "commit message that needs to be checked", + "exclusive_group": "group1", + }, ], }, { diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py index 6a2f8f400a..d60c36840f 100644 --- a/commitizen/commands/check.py +++ b/commitizen/commands/check.py @@ -23,6 +23,7 @@ def __init__(self, config: BaseConfig, arguments: Dict[str, str], cwd=os.getcwd( cwd: Current work directory """ self.commit_msg_file: Optional[str] = arguments.get("commit_msg_file") + self.commit_msg: Optional[str] = arguments.get("message") self.rev_range: Optional[str] = arguments.get("rev_range") self._valid_command_argument() @@ -31,7 +32,9 @@ def __init__(self, config: BaseConfig, arguments: Dict[str, str], cwd=os.getcwd( self.cz = factory.commiter_factory(self.config) def _valid_command_argument(self): - if bool(self.commit_msg_file) is bool(self.rev_range): + if not ( + bool(self.commit_msg_file) ^ bool(self.commit_msg) ^ bool(self.rev_range) + ): raise InvalidCommandArgumentError( ( "One and only one argument is required for check command! " @@ -77,6 +80,8 @@ def _get_commits(self): commit_title = commit_file.readline() commit_body = commit_file.read() return [git.GitCommit(rev="", title=commit_title, body=commit_body)] + elif self.commit_msg: + return [git.GitCommit(rev="", title="", body=self.commit_msg)] # Get commit messages from git log (--rev-range) return git.get_commits(end=self.rev_range) diff --git a/tests/commands/test_check_command.py b/tests/commands/test_check_command.py index 5973851e1c..f2bb99a0ca 100644 --- a/tests/commands/test_check_command.py +++ b/tests/commands/test_check_command.py @@ -226,3 +226,22 @@ def test_check_a_range_of_failed_git_commits(config, mocker): with pytest.raises(InvalidCommitMessageError) as excinfo: check_cmd() assert all([msg in str(excinfo.value) for msg in ill_formated_commits_msgs]) + + +def test_check_command_with_valid_message(config, mocker): + success_mock = mocker.patch("commitizen.out.success") + check_cmd = commands.Check( + config=config, arguments={"message": "fix(scope): some commit message"} + ) + + check_cmd() + success_mock.assert_called_once() + + +def test_check_command_with_invalid_message(config, mocker): + error_mock = mocker.patch("commitizen.out.error") + check_cmd = commands.Check(config=config, arguments={"message": "bad commit"}) + + with pytest.raises(InvalidCommitMessageError): + check_cmd() + error_mock.assert_called_once() From b207e6d3a26196465f87f2aae19fc4a615042222 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Mon, 31 Aug 2020 07:24:19 +0000 Subject: [PATCH 231/427] =?UTF-8?q?bump:=20version=202.1.0=20=E2=86=92=202?= =?UTF-8?q?.2.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77bd935d89..97800a50ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v2.2.0 (2020-08-31) + +### Feat + +- **cz_check**: cz check can read from a string input + ## v2.1.0 (2020-08-06) ### Refactor diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 9aa3f90365..8a124bf648 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.1.0" +__version__ = "2.2.0" diff --git a/pyproject.toml b/pyproject.toml index 07d13d826d..c66fadda25 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.1.0" +version = "2.2.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.1.0" +version = "2.2.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 38a1c60556407ae1c794be76f72772af99ad9107 Mon Sep 17 00:00:00 2001 From: Josix <wilson8507@gmail.com> Date: Tue, 1 Sep 2020 18:39:20 +0800 Subject: [PATCH 232/427] test(bump): Add commit-msgs for different increments --- tests/commands/test_bump_command.py | 69 +++++++++++++++++++---------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index f299e88afe..7b2a621be4 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -16,36 +16,71 @@ from tests.utils import create_file_and_commit +@pytest.mark.parametrize( + "commit_msg", + ( + "fix: username exception", + "fix(user): username exception", + "refactor: remove ini configuration support", + "refactor(config): remove ini configuration support", + "perf: update to use multiproess", + "perf(worker): update to use multiproess", + ), +) @pytest.mark.usefixtures("tmp_commitizen_project") -def test_bump_command(mocker): - # MINOR - create_file_and_commit("feat: new file") - +def test_bump_patch_increment(commit_msg, mocker): + create_file_and_commit(commit_msg) + # testargs = ["cz", "bump"] testargs = ["cz", "bump", "--yes"] mocker.patch.object(sys, "argv", testargs) cli.main() + tag_exists = git.tag_exist("0.1.1") + assert tag_exists is True + +@pytest.mark.parametrize("commit_msg", ("feat: new file", "feat(user): new file")) +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_bump_minor_increment(commit_msg, mocker): + create_file_and_commit(commit_msg) + testargs = ["cz", "bump", "--yes"] + mocker.patch.object(sys, "argv", testargs) + cli.main() tag_exists = git.tag_exist("0.2.0") assert tag_exists is True - # PATCH - create_file_and_commit("fix: username exception") - testargs = ["cz", "bump"] +@pytest.mark.usefixtures("tmp_commitizen_project") +@pytest.mark.parametrize( + "commit_msg", + ( + "feat: new user interface\n\nBREAKING CHANGE: age is no longer supported", + "feat(user): new user interface\n\nBREAKING CHANGE: age is no longer supported", + "BREAKING CHANGE: age is no longer supported", + "BREAKING-CHANGE: age is no longer supported", + "age is not longer supported!", + ), +) +def test_bump_major_increment(commit_msg, mocker): + create_file_and_commit(commit_msg) + + testargs = ["cz", "bump", "--yes"] mocker.patch.object(sys, "argv", testargs) cli.main() - tag_exists = git.tag_exist("0.2.1") + tag_exists = git.tag_exist("1.0.0") assert tag_exists is True + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_bump_command_prelease(mocker): # PRERELEASE create_file_and_commit("feat: location") - testargs = ["cz", "bump", "--prerelease", "alpha"] + testargs = ["cz", "bump", "--prerelease", "alpha", "--yes"] mocker.patch.object(sys, "argv", testargs) cli.main() - tag_exists = git.tag_exist("0.3.0a0") + tag_exists = git.tag_exist("0.2.0a0") assert tag_exists is True # PRERELEASE BUMP CREATES VERSION WITHOUT PRERELEASE @@ -53,19 +88,7 @@ def test_bump_command(mocker): mocker.patch.object(sys, "argv", testargs) cli.main() - tag_exists = git.tag_exist("0.3.0") - assert tag_exists is True - - # MAJOR - create_file_and_commit( - "feat: new user interface\n\nBREAKING CHANGE: age is no longer supported" - ) - - testargs = ["cz", "bump"] - mocker.patch.object(sys, "argv", testargs) - cli.main() - - tag_exists = git.tag_exist("1.0.0") + tag_exists = git.tag_exist("0.2.0") assert tag_exists is True From fa532b6d065b7e44ac13e877965c740830f0a68d Mon Sep 17 00:00:00 2001 From: Josix <wilson8507@gmail.com> Date: Tue, 1 Sep 2020 18:41:51 +0800 Subject: [PATCH 233/427] test(bump): Remove bump case with msg ends with `!` --- tests/commands/test_bump_command.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index 7b2a621be4..dfde03c300 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -57,7 +57,6 @@ def test_bump_minor_increment(commit_msg, mocker): "feat(user): new user interface\n\nBREAKING CHANGE: age is no longer supported", "BREAKING CHANGE: age is no longer supported", "BREAKING-CHANGE: age is no longer supported", - "age is not longer supported!", ), ) def test_bump_major_increment(commit_msg, mocker): From b26f408ea07758f34701b16d6785e15e23132b6b Mon Sep 17 00:00:00 2001 From: Josix <wilson8507@gmail.com> Date: Wed, 2 Sep 2020 02:56:11 +0800 Subject: [PATCH 234/427] test(bump): Add more MAJOR increment msgs for testing --- tests/commands/test_bump_command.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index dfde03c300..aff9dc6803 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -30,7 +30,6 @@ @pytest.mark.usefixtures("tmp_commitizen_project") def test_bump_patch_increment(commit_msg, mocker): create_file_and_commit(commit_msg) - # testargs = ["cz", "bump"] testargs = ["cz", "bump", "--yes"] mocker.patch.object(sys, "argv", testargs) cli.main() @@ -54,7 +53,11 @@ def test_bump_minor_increment(commit_msg, mocker): "commit_msg", ( "feat: new user interface\n\nBREAKING CHANGE: age is no longer supported", + "feat!: new user interface\n\nBREAKING CHANGE: age is no longer supported", + "feat!: new user interface", "feat(user): new user interface\n\nBREAKING CHANGE: age is no longer supported", + "feat(user)!: new user interface\n\nBREAKING CHANGE: age is no longer supported", + "feat(user)!: new user interface", "BREAKING CHANGE: age is no longer supported", "BREAKING-CHANGE: age is no longer supported", ), From 78c45299a0b40622e7afab1cfd48086fa0eef014 Mon Sep 17 00:00:00 2001 From: Alexandre Gerona <alecgerona@gmail.com> Date: Wed, 2 Sep 2020 23:39:25 +0800 Subject: [PATCH 235/427] feat(cli): rewrite cli instructions to be more succinct about what they require --- .../cz/conventional_commits/conventional_commits.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index 0a95a09199..de977d60f8 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -100,8 +100,7 @@ def questions(self) -> List[Dict[str, Any]]: "type": "input", "name": "scope", "message": ( - "Scope. Could be anything specifying place of the " - "commit change (users, db, poll):\n" + "What is the scope of this change? (class or file name): (press enter to skip)\n" ), "filter": parse_scope, }, @@ -110,16 +109,14 @@ def questions(self) -> List[Dict[str, Any]]: "name": "subject", "filter": parse_subject, "message": ( - "Subject. Concise description of the changes. " - "Imperative, lower case and no final dot:\n" + "Write a short and imperative summary of the code changes:\n" ), }, { "type": "input", "name": "body", "message": ( - "Body. Motivation for the change and contrast this " - "with previous behavior:\n" + "Provide additional contextual information about the code changes: (press enter to skip)\n" ), "filter": multiple_line_breaker, }, @@ -134,7 +131,7 @@ def questions(self) -> List[Dict[str, Any]]: "name": "footer", "message": ( "Footer. Information about Breaking Changes and " - "reference issues that this commit closes:\n" + "reference issues that this commit closes: (press enter to skip)\n" ), }, ] From 4965f0a6355fd2c05de04ce51df73127e5b72e99 Mon Sep 17 00:00:00 2001 From: Alexandre Gerona <alecgerona@gmail.com> Date: Wed, 2 Sep 2020 23:59:30 +0800 Subject: [PATCH 236/427] fix(cli): wrap the word enter with brackets --- commitizen/cz/conventional_commits/conventional_commits.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index de977d60f8..7681b49d5b 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -100,7 +100,7 @@ def questions(self) -> List[Dict[str, Any]]: "type": "input", "name": "scope", "message": ( - "What is the scope of this change? (class or file name): (press enter to skip)\n" + "What is the scope of this change? (class or file name): (press [enter] to skip)\n" ), "filter": parse_scope, }, @@ -116,7 +116,7 @@ def questions(self) -> List[Dict[str, Any]]: "type": "input", "name": "body", "message": ( - "Provide additional contextual information about the code changes: (press enter to skip)\n" + "Provide additional contextual information about the code changes: (press [enter] to skip)\n" ), "filter": multiple_line_breaker, }, @@ -131,7 +131,7 @@ def questions(self) -> List[Dict[str, Any]]: "name": "footer", "message": ( "Footer. Information about Breaking Changes and " - "reference issues that this commit closes: (press enter to skip)\n" + "reference issues that this commit closes: (press [enter] to skip)\n" ), }, ] From 683317be17b04bd6b8c34ac43f1cb79efb3f5cd4 Mon Sep 17 00:00:00 2001 From: Alexandre Gerona <alecgerona@gmail.com> Date: Thu, 3 Sep 2020 00:00:10 +0800 Subject: [PATCH 237/427] fix(cli): add guideline for subject input --- commitizen/cz/conventional_commits/conventional_commits.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index 7681b49d5b..ed04787ee8 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -109,7 +109,7 @@ def questions(self) -> List[Dict[str, Any]]: "name": "subject", "filter": parse_subject, "message": ( - "Write a short and imperative summary of the code changes:\n" + "Write a short and imperative summary of the code changes: (lower case and no period)\n" ), }, { From 93e093225a2fa7283637a62bfc6718853b2011ab Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 3 Sep 2020 07:50:58 +0000 Subject: [PATCH 238/427] =?UTF-8?q?bump:=20version=202.2.0=20=E2=86=92=202?= =?UTF-8?q?.3.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 11 +++++++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97800a50ed..2fd11964ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## v2.3.0 (2020-09-03) + +### Fix + +- **cli**: add guideline for subject input +- **cli**: wrap the word enter with brackets + +### Feat + +- **cli**: rewrite cli instructions to be more succinct about what they require + ## v2.2.0 (2020-08-31) ### Feat diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 8a124bf648..55e4709070 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.2.0" +__version__ = "2.3.0" diff --git a/pyproject.toml b/pyproject.toml index c66fadda25..14e6d0cb84 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.2.0" +version = "2.3.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.2.0" +version = "2.3.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 3f2f702042b31488a057b1ea336e360b1a0e2e7f Mon Sep 17 00:00:00 2001 From: Santiago <santiwilly@gmail.com> Date: Thu, 3 Sep 2020 14:10:28 +0200 Subject: [PATCH 239/427] ci(github-action): use personal access token Use personal access token instead of github token, in order to trigger new events (like pthonpublish) --- .github/workflows/bumpversion.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bumpversion.yml b/.github/workflows/bumpversion.yml index 1e9ce7da59..706e84aa17 100644 --- a/.github/workflows/bumpversion.yml +++ b/.github/workflows/bumpversion.yml @@ -18,4 +18,4 @@ jobs: - name: Create bump and changelog uses: commitizen-tools/commitizen-action@master with: - github_token: ${{ secrets.GITHUB_TOKEN }} + github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} From ef4a9bdd0b81f9084a7347ba03b83b591787b37c Mon Sep 17 00:00:00 2001 From: David Arnold <dar@xoe.solutions> Date: Sat, 5 Sep 2020 02:22:56 -0500 Subject: [PATCH 240/427] fix: conventional commit schema --- commitizen/cz/conventional_commits/conventional_commits.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index ed04787ee8..ba297f8ccb 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -171,9 +171,9 @@ def schema(self) -> str: return ( "<type>(<scope>): <subject>\n" "<BLANK LINE>\n" - "(BREAKING CHANGE: )<body>\n" + "<body>\n" "<BLANK LINE>\n" - "<footer>" + "(BREAKING CHANGE: )<footer>" ) def schema_pattern(self) -> str: From 492270e0fe68ee9b53a1ef7c826feea087fcb7b1 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Mon, 7 Sep 2020 08:49:57 +0000 Subject: [PATCH 241/427] =?UTF-8?q?bump:=20version=202.3.0=20=E2=86=92=202?= =?UTF-8?q?.3.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fd11964ef..a661f08292 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v2.3.1 (2020-09-07) + +### Fix + +- conventional commit schema + ## v2.3.0 (2020-09-03) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 55e4709070..3a5935a2d0 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.3.0" +__version__ = "2.3.1" diff --git a/pyproject.toml b/pyproject.toml index 14e6d0cb84..22a07f59d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.3.0" +version = "2.3.1" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.3.0" +version = "2.3.1" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From f3070c1f48893e8063cadba8d45f03aa123ac44c Mon Sep 17 00:00:00 2001 From: Jordan Su <newjordansu1126@gmail.com> Date: Thu, 17 Sep 2020 23:00:00 +0800 Subject: [PATCH 242/427] feat(cz_check): cz check can read commit message from pipe --- commitizen/commands/check.py | 10 ++++++--- tests/commands/test_check_command.py | 31 +++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py index d60c36840f..f326b44fa5 100644 --- a/commitizen/commands/check.py +++ b/commitizen/commands/check.py @@ -1,5 +1,6 @@ import os import re +import sys from typing import Dict, Optional from commitizen import factory, git, out @@ -32,9 +33,12 @@ def __init__(self, config: BaseConfig, arguments: Dict[str, str], cwd=os.getcwd( self.cz = factory.commiter_factory(self.config) def _valid_command_argument(self): - if not ( - bool(self.commit_msg_file) ^ bool(self.commit_msg) ^ bool(self.rev_range) - ): + number_args_provided = ( + bool(self.commit_msg_file) + bool(self.commit_msg) + bool(self.rev_range) + ) + if number_args_provided == 0 and not os.isatty(0): + self.commit_msg: Optional[str] = sys.stdin.read() + elif number_args_provided != 1: raise InvalidCommandArgumentError( ( "One and only one argument is required for check command! " diff --git a/tests/commands/test_check_command.py b/tests/commands/test_check_command.py index f2bb99a0ca..95eb007238 100644 --- a/tests/commands/test_check_command.py +++ b/tests/commands/test_check_command.py @@ -1,4 +1,5 @@ import sys +from io import StringIO from typing import List import pytest @@ -190,12 +191,12 @@ def test_check_a_range_of_git_commits_and_failed(config, mocker): error_mock.assert_called_once() -@pytest.mark.parametrize( - "args", [{"rev_range": "HEAD~10..master", "commit_msg_file": "some_file"}, {}] -) -def test_check_command_with_invalid_argment(args, config): +def test_check_command_with_invalid_argment(config): with pytest.raises(InvalidCommandArgumentError) as excinfo: - commands.Check(config=config, arguments=args) + commands.Check( + config=config, + arguments={"commit_msg_file": "some_file", "rev_range": "HEAD~10..master"}, + ) assert "One and only one argument is required for check command!" in str( excinfo.value ) @@ -245,3 +246,23 @@ def test_check_command_with_invalid_message(config, mocker): with pytest.raises(InvalidCommitMessageError): check_cmd() error_mock.assert_called_once() + + +def test_check_command_with_pipe_message(mocker, capsys): + testargs = ["cz", "check"] + mocker.patch.object(sys, "argv", testargs) + mocker.patch("sys.stdin", StringIO("fix(scope): some commit message")) + + cli.main() + out, _ = capsys.readouterr() + assert "Commit validation: successful!" in out + + +def test_check_command_with_pipe_message_and_failed(mocker): + testargs = ["cz", "check"] + mocker.patch.object(sys, "argv", testargs) + mocker.patch("sys.stdin", StringIO("bad commit message")) + + with pytest.raises(InvalidCommitMessageError) as excinfo: + cli.main() + assert "commit validation: failed!" in str(excinfo.value) From f44496f4d654c3abd9e1caac3a5d5f965c6dce17 Mon Sep 17 00:00:00 2001 From: Jordan Su <newjordansu1126@gmail.com> Date: Thu, 17 Sep 2020 23:43:19 +0800 Subject: [PATCH 243/427] docs(cz_check): the 'check' document is refactored and the usage of read commit message from pipe is added --- docs/auto_check.md | 65 +++++++++++++++++++++++++++++++++++++++ docs/check.md | 76 ++++++++++++++++------------------------------ 2 files changed, 91 insertions(+), 50 deletions(-) create mode 100644 docs/auto_check.md diff --git a/docs/auto_check.md b/docs/auto_check.md new file mode 100644 index 0000000000..9d746dda50 --- /dev/null +++ b/docs/auto_check.md @@ -0,0 +1,65 @@ +# Automatically check message before commit + +## About +To automatically check a commit message prior to committing, you can use a [git hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks). + +## How to +There are two common methods for installing the hook: +### Method 1: Add git hook through [pre-commit](https://pre-commit.com/) + +* Step 1: Install [pre-commit](https://pre-commit.com/) + +```sh +python -m pip install pre-commit +``` + +* Step 2: Create `.pre-commit-config.yaml` at your root directory with the following content + +```yaml +--- +repos: + - repo: https://github.com/commitizen-tools/commitizen + rev: v1.17.0 + hooks: + - id: commitizen + stages: [commit-msg] +``` + +* Step 3: Install the configuration into git hook through `pre-commit` + +```bash +pre-commit install --hook-type commit-msg +``` + +### Method 2: Manually add git hook +The command might be included inside of a Git hook (inside of `.git/hooks/` at the root of the project). + +The selected hook might be the file called commit-msg. + +This example shows how to use the check command inside of commit-msg. + +At the root of the project: + +```bash +cd .git/hooks +touch commit-msg +chmod +x commit-msg +``` + +Open the file and edit it: + +```sh +#!/bin/bash +MSG_FILE=$1 +cz check --commit-msg-file $MSG_FILE +``` + +Where `$1` is the name of the temporary file that contains the current commit message. To be more explicit, the previous variable is stored in another variable called `$MSG_FILE`, for didactic purposes. + +The `--commit-msg-file` flag is required, not optional. + +Each time you create a commit, automatically, this hook will analyze it. +If the commit message is invalid, it'll be rejected. + +The commit should follow the given committing rules; otherwise, it won't be accepted. + diff --git a/docs/check.md b/docs/check.md index 446326ada5..9150f608de 100644 --- a/docs/check.md +++ b/docs/check.md @@ -1,71 +1,47 @@ -## About +# Check +## About This feature checks whether the commit message follows the given committing rules. +If you want to setup an automatic check before every git commit, please refer to +[Automatically check message before commit](auto_check.md). -## Checking before the commit -To automatically check a commit message prior to committing, you can use a [git hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks). There are two common methods for installing the hook: - -### Method 1: Add git hook through [pre-commit](https://pre-commit.com/) +## Usage +There are three arguments that you can use one of them to check commit message. -* Step 1: Install [pre-commit](https://pre-commit.com/) +### Git Rev Range +If you'd like to check a commit's message after it has already been created, then you can specify the range of commits to check with `--rev-range REV_RANGE`. -```sh -python -m pip install pre-commit +```bash +$ cz check --rev-range REV_RANGE ``` -* Step 2: Create `.pre-commit-config.yaml` at your root directory with the following content +For example, if you'd like to check all commits on a branch, you can use `--rev-range master..HEAD`. Or, if you'd like to check all commits starting from when you first implemented commit message linting, you can use `--rev-range <first_commit_sha>..HEAD`. -```yaml ---- -repos: - - repo: https://github.com/commitizen-tools/commitizen - rev: v1.17.0 - hooks: - - id: commitizen - stages: [commit-msg] -``` +For more info on how git commit ranges work, you can check the [git documentation](https://git-scm.com/book/en/v2/Git-Tools-Revision-Selection#_commit_ranges). -* Step 3: Install the configuration into git hook through `pre-commit` +### Commit Message +There are two ways you can provide your plain message and check it. +#### Method 1: use -m or --message ```bash -pre-commit install --hook-type commit-msg +$ cz check --message MESSAGE ``` -### Method 2: Manually add git hook -The command might be included inside of a Git hook (inside of `.git/hooks/` at the root of the project). - -The selected hook might be the file called commit-msg. +In this option, MESSAGE is the commit message to be checked. -This example shows how to use the check command inside of commit-msg. - -At the root of the project: +#### Method 2: use pipe to pipe it to `cz check` ```bash -cd .git/hooks -touch commit-msg -chmod +x commit-msg +$ echo MESSAGE | cz check ``` -Open the file and edit it: +In this option, MESSAGE is piped to cz check and would be checked. -```sh -#!/bin/bash -MSG_FILE=$1 -cz check --commit-msg-file $MSG_FILE -``` +### Commit Message File -Where `$1` is the name of the temporary file that contains the current commit message. To be more explicit, the previous variable is stored in another variable called `$MSG_FILE`, for didactic purposes. - -The `--commit-msg-file` flag is required, not optional. - -Each time you create a commit, automatically, this hook will analyze it. -If the commit message is invalid, it'll be rejected. - -The commit should follow the given committing rules; otherwise, it won't be accepted. - -## Checking after the commit -If you'd like to check a commit's message after it has already been created, then you can specify the range of commits to check with `--rev-range REV_RANGE` - -For example, if you'd like to check all commits on a branch, you can use `--rev-range master..HEAD`. Or, if you'd like to check all commits starting from when you first implemented commit message linting, you can use `--rev-range <first_commit_sha>..HEAD`. +```bash +$ cz check --commit-msg-file COMMIT_MSG_FILE +``` -For more info on how git commit ranges work, you can check the [git documentation](https://git-scm.com/book/en/v2/Git-Tools-Revision-Selection#_commit_ranges). +In this option, COMMIT_MSG_FILE is the path of the temporal file that contains the commit message. +This argument can be useful when cooperating with git hook, please check [Automatically check message before commit](auto_check.md) for more information about how to use this argument with git hook. From 86a6c50edae12eca8adbf9435e9e9edeb7e55bb0 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Fri, 18 Sep 2020 09:42:38 +0000 Subject: [PATCH 244/427] =?UTF-8?q?bump:=20version=202.3.1=20=E2=86=92=202?= =?UTF-8?q?.4.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a661f08292..93bce17e36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v2.4.0 (2020-09-18) + +### Feat + +- **cz_check**: cz check can read commit message from pipe + ## v2.3.1 (2020-09-07) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 3a5935a2d0..3d67cd6bb4 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.3.1" +__version__ = "2.4.0" diff --git a/pyproject.toml b/pyproject.toml index 22a07f59d4..7039ae0b5d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.3.1" +version = "2.4.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.3.1" +version = "2.4.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 3b07f53e23f02ac8e3029e0fd68f2feb8fa109ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Fri, 18 Sep 2020 09:27:49 +0200 Subject: [PATCH 245/427] docs: add new jenkins tutorial Closes #78 --- docs/tutorials/jenkins_pipeline.md | 52 ++++++++++++++++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 53 insertions(+) create mode 100644 docs/tutorials/jenkins_pipeline.md diff --git a/docs/tutorials/jenkins_pipeline.md b/docs/tutorials/jenkins_pipeline.md new file mode 100644 index 0000000000..0d5d0693e2 --- /dev/null +++ b/docs/tutorials/jenkins_pipeline.md @@ -0,0 +1,52 @@ +# Create a new release with Jenkins Pipelines + +For this we are using the modern approach of [declarative pipelines](https://www.jenkins.io/doc/book/pipeline/). + +You must also ensure your jenkins instance supports docker. +Most modern jenkins systems do have support for it, [they have embraced it](https://www.jenkins.io/doc/book/pipeline/docker/). + +```groovy +pipeline { + agent { + any + } + environment { + CI = 'true' + } + stages { + stage('Bump version') { + when { + beforeAgent true + branch 'master' + not { + changelog '^bump:.+' + } + } + steps { + script { + useCz { + sh "cz bump --changelog" + } + // Here push back to your repository the new commit and tag + } + } + } + } +} + +def useCz(String authorName = 'Jenkins CI Server', String authorEmail = 'your-jenkins@email.com', String image = 'registry.hub.docker.com/commitizen/commitizen:latest', Closure body) { + docker + .image(image) + .inside("-u 0 -v $WORKSPACE:/workspace -w /workspace -e GIT_AUTHOR_NAME='${authorName}' -e GIT_AUTHOR_EMAIL='${authorEmail}'") { + sh "git config --global user.email '${authorName}'" + sh "git config --global user.name '${authorEmail}'" + body() + } +} +``` + +!!! warning + Using jenkins pipeline with any git plugin may require many different configurations, + you'll have to tinker with it until your pipelines properly detects git events. Check your + webhook in your git repository and check the "behaviors" and "build strategies" in + your pipeline settings. diff --git a/mkdocs.yml b/mkdocs.yml index 7089782453..038581b0b2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -21,6 +21,7 @@ nav: - Writing commits: 'tutorials/writing_commits.md' - GitLab CI: 'tutorials/gitlab_ci.md' - Github Actions: 'tutorials/github_actions.md' + - Jenkins pipeline: 'tutorials/jenkins_pipeline.md' - FAQ: 'faq.md' - Exit Codes: 'exit_codes.md' - Third-Party Commitizen Templates: 'third-party-commitizen.md' From 061f47c1434f2df2da49579ff92e489001ecd3ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Fri, 18 Sep 2020 09:30:30 +0200 Subject: [PATCH 246/427] docs: update gitlab and github ci tutorials --- docs/tutorials/github_actions.md | 40 +++++++++++--------------------- docs/tutorials/gitlab_ci.md | 20 ++++++++-------- 2 files changed, 23 insertions(+), 37 deletions(-) diff --git a/docs/tutorials/github_actions.md b/docs/tutorials/github_actions.md index c0784dac9f..8344d304ac 100644 --- a/docs/tutorials/github_actions.md +++ b/docs/tutorials/github_actions.md @@ -16,38 +16,24 @@ name: Bump version on: push: branches: - - master # another branch could be specified here + - master jobs: - build: + bump-version: if: "!startsWith(github.event.head_commit.message, 'bump:')" runs-on: ubuntu-latest - strategy: - matrix: - python-version: ['3.x'] + name: "Bump version and create changelog with commitizen" steps: - - uses: actions/checkout@v2 - with: - token: '${{ secrets.PERSONAL_ACCESS_TOKEN }}' - fetch-depth: 0 - - 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 -m pip install -U commitizen - - name: Create bump - run: | - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - cz bump --yes - - name: Push changes - uses: Woile/github-push-action@master - with: - github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} - tags: "true" + - name: Check out + uses: actions/checkout@v2 + with: + token: '${{ secrets.PERSONAL_ACCESS_TOKEN }}' + fetch-depth: 0 + - name: Create bump and changelog + uses: commitizen-tools/commitizen-action@master + with: + github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + ``` Push to master and that's it. diff --git a/docs/tutorials/gitlab_ci.md b/docs/tutorials/gitlab_ci.md index 80cbd4028b..9be03d1966 100644 --- a/docs/tutorials/gitlab_ci.md +++ b/docs/tutorials/gitlab_ci.md @@ -1,10 +1,10 @@ -### Create a new release using GitLab CI +## Create a new release using GitLab CI For this example, we have a `python/django` application and `Docker` as a containerization tool. -*Goal*: Bump a new version every time that a change occurs on the `master` branch. The bump should be executed automatically by the `CI` process. +_Goal_: Bump a new version every time that a change occurs on the `master` branch. The bump should be executed automatically by the `CI` process. -#### Development Workflow: +### Development Workflow 1. A developer creates a new commit on any branch (except `master`) 2. A developer creates a merge request (MR) against `master` branch @@ -12,7 +12,7 @@ For this example, we have a `python/django` application and `Docker` as a contai 4. For simplification, we store the software version in a file called `VERSION`. You can use any file that you want as `commitizen` supports it. 5. The commit message executed automatically by the `CI` must include `[skip-ci]` in the message; otherwise, the process will generate a loop. You can define the message structure in [commitizen](https://commitizen-tools.github.io/commitizen/bump/) as well. -#### Gitlab Configuration: +### Gitlab Configuration To be able to change files and push new changes with `Gitlab CI` runners, we need to have a `ssh` key and configure a git user. @@ -40,15 +40,15 @@ If you have more projects under the same organization, you can reuse the deploy tip: If the CI raise some errors, try to unprotected the private key. -#### Defining GitLab CI Pipeline +### Defining GitLab CI Pipeline 1. Create a `.gitlab-ci.yaml` file that contains `stages` and `jobs` configurations. You can find more info [here](https://docs.gitlab.com/ee/ci/quick_start/). 2. Define `stages` and `jobs`. For this example, we define two `stages` with one `job` each one. - * Test the application. - * Auto bump the version. This means changing the file/s that reflects the version, creating a new commit and git tag. + - Test the application. + - Auto bump the version. This means changing the file/s that reflects the version, creating a new commit and git tag. -#### Stages and Jobs +### Stages and Jobs ```yaml image: docker:latest @@ -76,7 +76,7 @@ auto-bump: stage: auto-bump image: python:3.6 before_script: - - 'which ssh-agent || ( apt-get update -qy && apt-get install openssh-client -qqy )' + - "which ssh-agent || ( apt-get update -qy && apt-get install openssh-client -qqy )" - eval `ssh-agent -s` - echo "${SSH_PRIVATE_KEY}" | tr -d '\r' | ssh-add - > /dev/null # add ssh key - pip3 install -U Commitizen # install commitizen @@ -102,7 +102,7 @@ auto-bump: - master artifacts: paths: - - variables + - 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. From d8e9badae9d5ab1c088d5bb0932f3977db24d442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Fri, 18 Sep 2020 09:31:05 +0200 Subject: [PATCH 247/427] ci: add token to bumpversion.yml on checkout --- .github/workflows/bumpversion.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/bumpversion.yml b/.github/workflows/bumpversion.yml index 706e84aa17..86f6901793 100644 --- a/.github/workflows/bumpversion.yml +++ b/.github/workflows/bumpversion.yml @@ -15,6 +15,7 @@ jobs: uses: actions/checkout@v2 with: fetch-depth: 0 + token: '${{ secrets.PERSONAL_ACCESS_TOKEN }}' - name: Create bump and changelog uses: commitizen-tools/commitizen-action@master with: From 5b56b7e2f9c357cf5ec0b439e6f7b398a5e9aa4d Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 4 Oct 2020 12:14:42 +0800 Subject: [PATCH 248/427] fix(cz_customize): make schema_pattern customiziable through config for cz_customize --- commitizen/cz/customize/customize.py | 3 +++ docs/customization.md | 2 ++ tests/test_cz_customize.py | 7 +++++++ 3 files changed, 12 insertions(+) diff --git a/commitizen/cz/customize/customize.py b/commitizen/cz/customize/customize.py index 122dc9a4ee..1c0bb98baf 100644 --- a/commitizen/cz/customize/customize.py +++ b/commitizen/cz/customize/customize.py @@ -45,6 +45,9 @@ def message(self, answers: dict) -> str: def example(self) -> Optional[str]: return self.custom_settings.get("example") + def schema_pattern(self) -> Optional[str]: + return self.custom_settings.get("schema_pattern") + def schema(self) -> Optional[str]: return self.custom_settings.get("schema") diff --git a/docs/customization.md b/docs/customization.md index 0602b9cecb..2478bdc5f7 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -20,6 +20,7 @@ name = "cz_customize" message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" example = "feature: this feature enable customize through config file" schema = "<type>: <body>" +schema_pattern = "(feature|bug fix):(\\s.*)" bump_pattern = "^(break|new|fix|hotfix)" bump_map = {"break" = "MAJOR", "new" = "MINOR", "fix" = "PATCH", "hotfix" = "PATCH"} info_path = "cz_customize_info.txt" @@ -53,6 +54,7 @@ message = "Do you want to add body message in commit?" | `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`. | +| `schema_pattern` | `str` | `None` | (OPTIONAL) The regular expression used to do commit message validation. Used by `cz check`. | | `info_path` | `str` | `None` | (OPTIONAL) The path to the file that contains explanation of the commit rules. Used by `cz info`. If not provided `cz info`, will load `info` instead. | | `info` | `str` | `None` | (OPTIONAL) Explanation of the commit rules. Used by `cz info`. | | `bump_map` | `dict` | `None` | (OPTIONAL) Dictionary mapping the extracted information to a `SemVer` increment type (`MAJOR`, `MINOR`, `PATCH`) | diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py index 11b14ab596..2cf0a5917d 100644 --- a/tests/test_cz_customize.py +++ b/tests/test_cz_customize.py @@ -12,6 +12,8 @@ def config(): message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" example = "feature: this feature enable customize through config file" schema = "<type>: <body>" + schema_pattern = "(feature|bug fix):(\\s.*)" + bump_pattern = "^(break|new|fix|hotfix)" bump_map = {"break" = "MAJOR", "new" = "MINOR", "fix" = "PATCH", "hotfix" = "PATCH"} info = "This is a customized cz." @@ -114,6 +116,11 @@ def test_schema(config): assert "<type>: <body>" in cz.schema() +def test_schema_pattern(config): + cz = CustomizeCommitsCz(config) + assert r"(feature|bug fix):(\s.*)" in cz.schema_pattern() + + def test_info(config): cz = CustomizeCommitsCz(config) assert "This is a customized cz." in cz.info() From 86bbcd5d250b1fd193e0589f856a180fe0f834f6 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sun, 4 Oct 2020 06:34:34 +0000 Subject: [PATCH 249/427] =?UTF-8?q?bump:=20version=202.4.0=20=E2=86=92=202?= =?UTF-8?q?.4.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93bce17e36..af6109f17b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v2.4.1 (2020-10-04) + +### Fix + +- **cz_customize**: make schema_pattern customiziable through config for cz_customize + ## v2.4.0 (2020-09-18) ### Feat diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 3d67cd6bb4..54499df347 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.4.0" +__version__ = "2.4.1" diff --git a/pyproject.toml b/pyproject.toml index 7039ae0b5d..88d3f2efdf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.4.0" +version = "2.4.1" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.4.0" +version = "2.4.1" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 0be6d0bb19d272fc52610180b0fd463942ce2479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sun, 4 Oct 2020 12:33:09 +0200 Subject: [PATCH 250/427] docs: correct markdown on github actions tutorial page --- docs/tutorials/github_actions.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/tutorials/github_actions.md b/docs/tutorials/github_actions.md index 8344d304ac..1c6494195f 100644 --- a/docs/tutorials/github_actions.md +++ b/docs/tutorials/github_actions.md @@ -4,6 +4,7 @@ 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`. From 863a785b595dc61cd6f22b93ce15fa9c3bf0571f Mon Sep 17 00:00:00 2001 From: Christian Eland <eland.christian@gmail.com> Date: Sat, 24 Oct 2020 23:47:52 -0300 Subject: [PATCH 251/427] fix(commands/bump): Add NoneIncrementExit to fix git fatal error when creating existing tag raises NoneIncrementExit if `increment is None and new_tag_version == current_tag_version` #280 --- commitizen/commands/bump.py | 12 +++++++++ commitizen/exceptions.py | 4 +++ tests/commands/test_bump_command.py | 39 +++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 36ea7e2524..512a8a130e 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -12,6 +12,7 @@ DryRunExit, ExpectedExit, NoCommitsFoundError, + NoneIncrementExit, NoPatternMapError, NotAGitProjectError, NoVersionSpecifiedError, @@ -108,6 +109,12 @@ def __call__(self): # noqa: C901 if increment is None: increment = self.find_increment(commits) + # if increment != 'PATCH' and increment != 'MINOR': + # if increment != 'MAJOR': + # import ipdb; ipdb.set_trace() + + # git.tag_exist() + # Increment is removed when current and next version # are expected to be prereleases. if prerelease and current_version_instance.is_prerelease: @@ -117,6 +124,7 @@ def __call__(self): # noqa: C901 current_version, increment, prerelease=prerelease ) new_tag_version = bump.create_tag(new_version, tag_format=tag_format) + message = bump.create_commit_message( current_version, new_version, bump_commit_message ) @@ -128,6 +136,9 @@ def __call__(self): # noqa: C901 f"increment detected: {increment}\n" ) + if increment is None and new_tag_version == current_tag_version: + raise NoneIncrementExit() + # Do not perform operations over files or git. if dry_run: raise DryRunExit() @@ -157,6 +168,7 @@ def __call__(self): # noqa: C901 c = git.commit(message, args=self._get_commit_args()) if c.return_code != 0: raise BumpCommitFailedError(f'git.commit error: "{c.err.strip()}"') + c = git.tag(new_tag_version) if c.return_code != 0: raise BumpTagFailedError(c.err) diff --git a/commitizen/exceptions.py b/commitizen/exceptions.py index 9a63002c6a..6a490c5218 100644 --- a/commitizen/exceptions.py +++ b/commitizen/exceptions.py @@ -53,6 +53,10 @@ class DryRunExit(ExpectedExit): pass +class NoneIncrementExit(ExpectedExit): + ... + + class NoCommitizenFoundException(CommitizenException): exit_code = ExitCode.NO_COMMITIZEN_FOUND diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index aff9dc6803..73982a336d 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -1,7 +1,10 @@ +import inspect import sys +from unittest.mock import MagicMock import pytest +import commitizen.commands.bump as bump from commitizen import cli, cmd, git from commitizen.exceptions import ( BumpTagFailedError, @@ -9,6 +12,7 @@ DryRunExit, ExpectedExit, NoCommitsFoundError, + NoneIncrementExit, NoPatternMapError, NotAGitProjectError, NoVersionSpecifiedError, @@ -262,3 +266,38 @@ def test_bump_in_non_git_project(tmpdir, config, mocker): with pytest.raises(NotAGitProjectError): with pytest.raises(ExpectedExit): cli.main() + + +def test_none_increment_exit_should_be_a_class(): + assert inspect.isclass(NoneIncrementExit) + + +def test_none_increment_exit_should_be_expected_exit_subclass(): + assert issubclass(NoneIncrementExit, ExpectedExit) + + +def test_none_increment_exit_should_exist_in_bump(): + assert hasattr(bump, "NoneIncrementExit") + + +def test_none_increment_exit_is_exception(): + assert bump.NoneIncrementExit == NoneIncrementExit + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_none_increment_should_not_call_git_tag(mocker, tmp_commitizen_project): + create_file_and_commit("test(test_get_all_droplets): fix bad comparison test") + testargs = ["cz", "bump", "--yes"] + mocker.patch.object(sys, "argv", testargs) + + # stash git.tag for later restore + stashed_git_tag = git.tag + dummy_value = git.tag("0.0.2") + git.tag = MagicMock(return_value=dummy_value) + + with pytest.raises(NoneIncrementExit): + cli.main() + git.tag.assert_not_called() + + # restore pop stashed + git.tag = stashed_git_tag From 9795466a7d7a243a1ac8614ae92a7ef98cff2abe Mon Sep 17 00:00:00 2001 From: Christian Eland <eland.christian@gmail.com> Date: Sun, 25 Oct 2020 00:30:25 -0300 Subject: [PATCH 252/427] refactor(commands/bump): Remove comment and changed ... for pass --- commitizen/commands/bump.py | 7 ------- commitizen/exceptions.py | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 512a8a130e..5e72f0a0e8 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -109,11 +109,6 @@ def __call__(self): # noqa: C901 if increment is None: increment = self.find_increment(commits) - # if increment != 'PATCH' and increment != 'MINOR': - # if increment != 'MAJOR': - # import ipdb; ipdb.set_trace() - - # git.tag_exist() # Increment is removed when current and next version # are expected to be prereleases. @@ -124,7 +119,6 @@ def __call__(self): # noqa: C901 current_version, increment, prerelease=prerelease ) new_tag_version = bump.create_tag(new_version, tag_format=tag_format) - message = bump.create_commit_message( current_version, new_version, bump_commit_message ) @@ -168,7 +162,6 @@ def __call__(self): # noqa: C901 c = git.commit(message, args=self._get_commit_args()) if c.return_code != 0: raise BumpCommitFailedError(f'git.commit error: "{c.err.strip()}"') - c = git.tag(new_tag_version) if c.return_code != 0: raise BumpTagFailedError(c.err) diff --git a/commitizen/exceptions.py b/commitizen/exceptions.py index 6a490c5218..84219f7fd1 100644 --- a/commitizen/exceptions.py +++ b/commitizen/exceptions.py @@ -54,7 +54,7 @@ class DryRunExit(ExpectedExit): class NoneIncrementExit(ExpectedExit): - ... + pass class NoCommitizenFoundException(CommitizenException): From 74738af8e7b6865ae2df9e12e733ad704d0a367f Mon Sep 17 00:00:00 2001 From: Christian Eland <eland.christian@gmail.com> Date: Sun, 25 Oct 2020 00:34:48 -0300 Subject: [PATCH 253/427] style(commands/bump): fix format --- commitizen/commands/bump.py | 1 - 1 file changed, 1 deletion(-) diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 5e72f0a0e8..b9597f322c 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -109,7 +109,6 @@ def __call__(self): # noqa: C901 if increment is None: increment = self.find_increment(commits) - # Increment is removed when current and next version # are expected to be prereleases. if prerelease and current_version_instance.is_prerelease: From 2a94361fde13c3c138db23c3d9c43c25f49dee18 Mon Sep 17 00:00:00 2001 From: Christian Eland <eland.christian@gmail.com> Date: Sun, 25 Oct 2020 00:52:59 -0300 Subject: [PATCH 254/427] fix(init.py): mypy error (types) closes #285 --- commitizen/commands/init.py | 4 ++-- commitizen/git.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/commitizen/commands/init.py b/commitizen/commands/init.py index 1c459d5ed4..1bfb643f0e 100644 --- a/commitizen/commands/init.py +++ b/commitizen/commands/init.py @@ -47,7 +47,7 @@ def __call__(self): def _ask_config_path(self) -> str: name = questionary.select( "Please choose a supported config file: (default: pyproject.toml)", - choices=config_files, + choices=config_files, # type: ignore default="pyproject.toml", style=self.cz.style, ).ask() @@ -79,7 +79,7 @@ def _ask_tag(self) -> str: latest_tag = questionary.select( "Please choose the latest tag: ", - choices=get_tag_names(), + choices=get_tag_names(), # type: ignore style=self.cz.style, ).ask() diff --git a/commitizen/git.py b/commitizen/git.py index 81aa9166cf..06ad240367 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -123,7 +123,7 @@ def get_latest_tag_name() -> Optional[str]: return c.out.strip() -def get_tag_names() -> Optional[List[str]]: +def get_tag_names() -> List[Optional[str]]: c = cmd.run("git tag --list") if c.err: return [] From a62354f2cf0c7eeab59673df9ec175a302875d51 Mon Sep 17 00:00:00 2001 From: Christian Eland <eland.christian@gmail.com> Date: Sun, 25 Oct 2020 02:07:41 -0300 Subject: [PATCH 255/427] test(test_git): get_tag_names should have List[Optional[str]] annotation issue #285 --- tests/test_git.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_git.py b/tests/test_git.py index 92abc2f040..650b720d3c 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -1,3 +1,6 @@ +import inspect +from typing import List, Optional, Union + import pytest from commitizen import git @@ -68,3 +71,9 @@ def test_get_commits_author_and_email(): assert commit.author is not "" assert "@" in commit.author_email + + +def test_get_tag_names_has_correct_arrow_annotation(): + arrow_annotation = inspect.getfullargspec(git.get_tag_names).annotations["return"] + + assert arrow_annotation == List[Optional[str]] From 6370be030f3c3bf4c75f6c2165fd0c698185f771 Mon Sep 17 00:00:00 2001 From: Christian Eland <eland.christian@gmail.com> Date: Sun, 25 Oct 2020 02:25:43 -0300 Subject: [PATCH 256/427] test(test_git.py): F401 'typing.Union' imported but unused --- tests/test_git.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_git.py b/tests/test_git.py index 650b720d3c..bcbca58bb0 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -1,5 +1,5 @@ import inspect -from typing import List, Optional, Union +from typing import List, Optional import pytest From 14b6c382ff96e37ba118ba1b75073b0d2313ee91 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Mon, 26 Oct 2020 19:57:55 +0000 Subject: [PATCH 257/427] =?UTF-8?q?bump:=20version=202.4.1=20=E2=86=92=202?= =?UTF-8?q?.4.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 11 +++++++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af6109f17b..8764b7e342 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## v2.4.2 (2020-10-26) + +### Fix + +- **init.py**: mypy error (types) +- **commands/bump**: Add NoneIncrementExit to fix git fatal error when creating existing tag + +### Refactor + +- **commands/bump**: Remove comment and changed ... for pass + ## v2.4.1 (2020-10-04) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 54499df347..60be088dcf 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.4.1" +__version__ = "2.4.2" diff --git a/pyproject.toml b/pyproject.toml index 88d3f2efdf..7bbb2fe2e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.4.1" +version = "2.4.2" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.4.1" +version = "2.4.2" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 6fba3ab3c9e40b85aa4e7be39207ae44d8a54be3 Mon Sep 17 00:00:00 2001 From: Jan Willhaus <jan.willhaus@cloud.ionos.com> Date: Wed, 4 Nov 2020 13:17:44 +0100 Subject: [PATCH 258/427] feat(commands/changelog): add config file options for start_rev and incremental --- commitizen/commands/changelog.py | 8 +++- commitizen/defaults.py | 2 + tests/commands/test_changelog_command.py | 50 ++++++++++++++++++++++++ tests/test_conf.py | 4 ++ 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index e177062b58..62d175d27d 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -29,11 +29,15 @@ def __init__(self, config: BaseConfig, args): self.config: BaseConfig = config self.cz = factory.commiter_factory(self.config) - self.start_rev = args.get("start_rev") + self.start_rev = args.get("start_rev") or self.config.settings.get( + "changelog_start_rev" + ) self.file_name = args.get("file_name") or self.config.settings.get( "changelog_file" ) - self.incremental = args["incremental"] + self.incremental = args["incremental"] or self.config.settings.get( + "changelog_incremental" + ) self.dry_run = args["dry_run"] self.unreleased_version = args["unreleased_version"] self.change_type_map = ( diff --git a/commitizen/defaults.py b/commitizen/defaults.py index 8c871840ed..97854453ea 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -11,6 +11,8 @@ "tag_format": None, # example v$version "bump_message": None, # bumped v$current_version to $new_version "changelog_file": "CHANGELOG.md", + "changelog_incremental": False, + "changelog_start_rev": None, } MAJOR = "MAJOR" diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index 09a96dfd72..d52d157c78 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -20,6 +20,11 @@ def changelog_path() -> str: return os.path.join(os.getcwd(), "CHANGELOG.md") +@pytest.fixture() +def config_path() -> str: + return os.path.join(os.getcwd(), "pyproject.toml") + + @pytest.mark.usefixtures("tmp_commitizen_project") def test_changelog_on_empty_project(mocker): testargs = ["cz", "changelog", "--dry-run"] @@ -389,3 +394,48 @@ def test_breaking_change_content_v1(mocker, capsys): "## Unreleased\n\n### Feat\n\n- **users**: email pattern corrected\n\n" "### BREAKING CHANGE\n\n- migrate by renaming user to users\n\n" ) + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_changelog_config_flag_increment(mocker, changelog_path, config_path): + + with open(config_path, "a") as f: + f.write("changelog_incremental = true\n") + with open(changelog_path, "a") as f: + f.write("\nnote: this should be persisted using increment\n") + + create_file_and_commit("feat: add new output") + + testargs = ["cz", "changelog"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + + with open(changelog_path, "r") as f: + out = f.read() + + assert "this should be persisted using increment" in out + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_changelog_config_start_rev_option(mocker, capsys, config_path): + + # create commit and tag + create_file_and_commit("feat: new file") + testargs = ["cz", "bump", "--yes"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + capsys.readouterr() + + create_file_and_commit("feat: after 0.2.0") + create_file_and_commit("feat: after 0.2") + + with open(config_path, "a") as f: + f.write('changelog_start_rev = "0.2.0"\n') + + testargs = ["cz", "changelog", "--dry-run"] + mocker.patch.object(sys, "argv", testargs) + with pytest.raises(DryRunExit): + cli.main() + + out, _ = capsys.readouterr() + assert out == "## Unreleased\n\n### Feat\n\n- after 0.2\n- after 0.2.0\n\n" diff --git a/tests/test_conf.py b/tests/test_conf.py index 241f2117d5..ba621bd635 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -32,6 +32,8 @@ "version_files": ["commitizen/__version__.py", "pyproject.toml"], "style": [["pointer", "reverse"], ["question", "underline"]], "changelog_file": "CHANGELOG.md", + "changelog_incremental": False, + "changelog_start_rev": None, } _new_settings = { @@ -42,6 +44,8 @@ "version_files": ["commitizen/__version__.py", "pyproject.toml"], "style": [["pointer", "reverse"], ["question", "underline"]], "changelog_file": "CHANGELOG.md", + "changelog_incremental": False, + "changelog_start_rev": None, } _read_settings = { From 9e9fdb2416f97d661a2f759440b656fe130f1c74 Mon Sep 17 00:00:00 2001 From: Jan Willhaus <jan.willhaus@cloud.ionos.com> Date: Wed, 4 Nov 2020 13:31:49 +0100 Subject: [PATCH 259/427] docs(changelog): add config file options `changelog_incremental` and `changelog_start_rev` --- docs/changelog.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index a50b906df1..41a5615d6c 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -114,6 +114,8 @@ cz changelog --file-name="CHANGES.md" ### `incremental` +This flag can be set in the `toml` file with the key `changelog_incremental` under `tools.commitizen` + Benefits: - Build from latest version found in changelog, this is useful if you have a different changelog and want to use commitizen @@ -124,6 +126,28 @@ Benefits: cz changelog --incremental ``` +```toml +[tools.commitizen] +# ... +changelog_incremental = true +``` + +### `start-rev` + +This value can be set in the `toml` file with the key `changelog_start_rev` under `tools.commitizen` + +Start from a given git rev to generate the changelog. Commits before that rev will not be considered. This is especially useful for long-running projects adopting conventional commits, where old commit messages might fail to be parsed for changelog generation. + +```bash +cz changelog --start-rev="v0.2.0" +``` + +```toml +[tools.commitizen] +# ... +changelog_start_rev = "v0.2.0" +``` + ## Hooks Supported hook methods: From 1ca22f4ae410c413c92d935bf886e0a9f36ab6ac Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 4 Nov 2020 12:53:53 +0000 Subject: [PATCH 260/427] =?UTF-8?q?bump:=20version=202.4.2=20=E2=86=92=202?= =?UTF-8?q?.5.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8764b7e342..dc7f37ef54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v2.5.0 (2020-11-04) + +### Feat + +- **commands/changelog**: add config file options for start_rev and incremental + ## v2.4.2 (2020-10-26) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 60be088dcf..50062f87c0 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.4.2" +__version__ = "2.5.0" diff --git a/pyproject.toml b/pyproject.toml index 7bbb2fe2e1..4c4cdb786a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.4.2" +version = "2.5.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.4.2" +version = "2.5.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 92630577ef6144f2ed7718754b05c6c820834587 Mon Sep 17 00:00:00 2001 From: Jan Willhaus <mail@janwillhaus.de> Date: Wed, 4 Nov 2020 14:13:10 +0100 Subject: [PATCH 261/427] feat(commands/bump): add config option to create changelog on bump --- commitizen/commands/bump.py | 4 +++- commitizen/defaults.py | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index b9597f322c..6a57fdb867 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -37,7 +37,9 @@ def __init__(self, config: BaseConfig, arguments: dict): }, } self.cz = factory.commiter_factory(self.config) - self.changelog = arguments["changelog"] + self.changelog = arguments["changelog"] or self.config.settings.get( + "update_changelog_on_bump" + ) self.no_verify = arguments["no_verify"] self.check_consistency = arguments["check_consistency"] diff --git a/commitizen/defaults.py b/commitizen/defaults.py index 97854453ea..4f63c99d91 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -13,6 +13,7 @@ "changelog_file": "CHANGELOG.md", "changelog_incremental": False, "changelog_start_rev": None, + "update_changelog_on_bump": False, } MAJOR = "MAJOR" From 7a2bf967c7ca93eea7737161e4f183620558d556 Mon Sep 17 00:00:00 2001 From: Jan Willhaus <mail@janwillhaus.de> Date: Wed, 4 Nov 2020 14:13:10 +0100 Subject: [PATCH 262/427] test: provide tests for update_changelog_on_bump config option --- tests/commands/conftest.py | 12 +++++++++ tests/commands/test_bump_command.py | 33 ++++++++++++++++++++++++ tests/commands/test_changelog_command.py | 11 -------- tests/test_conf.py | 2 ++ 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/tests/commands/conftest.py b/tests/commands/conftest.py index cadf369f06..25bab04464 100644 --- a/tests/commands/conftest.py +++ b/tests/commands/conftest.py @@ -1,3 +1,5 @@ +import os + import pytest from commitizen import defaults @@ -9,3 +11,13 @@ def config(): _config = BaseConfig() _config.settings.update({"name": defaults.name}) return _config + + +@pytest.fixture() +def changelog_path() -> str: + return os.path.join(os.getcwd(), "CHANGELOG.md") + + +@pytest.fixture() +def config_path() -> str: + return os.path.join(os.getcwd(), "pyproject.toml") diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index 73982a336d..ce19c136bc 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -301,3 +301,36 @@ def test_none_increment_should_not_call_git_tag(mocker, tmp_commitizen_project): # restore pop stashed git.tag = stashed_git_tag + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_bump_with_changelog_arg(mocker, changelog_path): + create_file_and_commit("feat(user): new file") + testargs = ["cz", "bump", "--yes", "--changelog"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + tag_exists = git.tag_exist("0.2.0") + assert tag_exists is True + + with open(changelog_path, "r") as f: + out = f.read() + assert out.startswith("#") + assert "0.2.0" in out + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_bump_with_changelog_config(mocker, changelog_path, config_path): + create_file_and_commit("feat(user): new file") + with open(config_path, "a") as fp: + fp.write("update_changelog_on_bump = true\n") + + testargs = ["cz", "bump", "--yes"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + tag_exists = git.tag_exist("0.2.0") + assert tag_exists is True + + with open(changelog_path, "r") as f: + out = f.read() + assert out.startswith("#") + assert "0.2.0" in out diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index d52d157c78..aceaaf9d96 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -1,4 +1,3 @@ -import os import sys from datetime import date @@ -15,16 +14,6 @@ from tests.utils import create_file_and_commit -@pytest.fixture() -def changelog_path() -> str: - return os.path.join(os.getcwd(), "CHANGELOG.md") - - -@pytest.fixture() -def config_path() -> str: - return os.path.join(os.getcwd(), "pyproject.toml") - - @pytest.mark.usefixtures("tmp_commitizen_project") def test_changelog_on_empty_project(mocker): testargs = ["cz", "changelog", "--dry-run"] diff --git a/tests/test_conf.py b/tests/test_conf.py index ba621bd635..919fb46e78 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -34,6 +34,7 @@ "changelog_file": "CHANGELOG.md", "changelog_incremental": False, "changelog_start_rev": None, + "update_changelog_on_bump": False, } _new_settings = { @@ -46,6 +47,7 @@ "changelog_file": "CHANGELOG.md", "changelog_incremental": False, "changelog_start_rev": None, + "update_changelog_on_bump": False, } _read_settings = { From 9501feada1e744ba00546b118a7cba456e2ce660 Mon Sep 17 00:00:00 2001 From: Jan Willhaus <mail@janwillhaus.de> Date: Wed, 4 Nov 2020 14:13:10 +0100 Subject: [PATCH 263/427] docs(bump): document usage of the `update_changelog_on_bump` flag --- docs/bump.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/bump.md b/docs/bump.md index 6fb3618b8e..3ff2d6a286 100644 --- a/docs/bump.md +++ b/docs/bump.md @@ -216,6 +216,19 @@ Some examples bump_message = "release $current_version → $new_version [skip-ci]" ``` +--- + +### `update_changelog_on_bump` + +When set to `true` the changelog is always updated incrementally when running `cz bump`, so the user does not have to provide the `--changelog` flag every time. + +defaults to: `false` + +```toml +[tool.commitizen] +update_changelog_on_bump = true +``` + ## Custom bump Read the [customizing section](./customization.md). From f1577b3925d522214858a5973beeff0eee9d79d0 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 4 Nov 2020 15:11:18 +0000 Subject: [PATCH 264/427] =?UTF-8?q?bump:=20version=202.5.0=20=E2=86=92=202?= =?UTF-8?q?.6.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc7f37ef54..a9613cd61a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v2.6.0 (2020-11-04) + +### Feat + +- **commands/bump**: add config option to create changelog on bump + ## v2.5.0 (2020-11-04) ### Feat diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 50062f87c0..e5e59e38da 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.5.0" +__version__ = "2.6.0" diff --git a/pyproject.toml b/pyproject.toml index 4c4cdb786a..66157ab722 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.5.0" +version = "2.6.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.5.0" +version = "2.6.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From f00750eb6cba6d57a4902f29c35dcf81350e93dc Mon Sep 17 00:00:00 2001 From: harens <harensdeveloper@gmail.com> Date: Tue, 6 Oct 2020 11:50:53 +0100 Subject: [PATCH 265/427] Add Homebrew Instructions --- docs/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/README.md b/docs/README.md index 5bd9e0af85..4b87077126 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,6 +5,7 @@ Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg?st release](https://img.shields.io/pypi/v/commitizen.svg?style=flat-square)](https://pypi.org/project/commitizen/) [![Supported versions](https://img.shields.io/pypi/pyversions/commitizen.svg?style=flat-square)](https://pypi.org/project/commitizen/) +[![homebrew](https://img.shields.io/homebrew/v/commitizen?color=teal&style=flat-square)](https://formulae.brew.sh/formula/commitizen) [![Codecov](https://img.shields.io/codecov/c/github/commitizen-tools/commitizen.svg?style=flat-square)](https://codecov.io/gh/commitizen-tools/commitizen) ![Using commitizen cli](images/demo.gif) @@ -62,6 +63,14 @@ pip install -U commitizen poetry add commitizen --dev ``` +### macOS + +On macOS, it can also be installed via [homebrew](https://formulae.brew.sh/formula/commitizen): + +```bash +brew install commitizen +``` + ## Usage ### Committing From ae03624d512557804d86bcfbe8497035bb27ed74 Mon Sep 17 00:00:00 2001 From: harens <harensdeveloper@gmail.com> Date: Tue, 6 Oct 2020 12:35:50 +0100 Subject: [PATCH 266/427] Homebrew Github Action Added --- .github/workflows/homebrewpublish.yaml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/homebrewpublish.yaml diff --git a/.github/workflows/homebrewpublish.yaml b/.github/workflows/homebrewpublish.yaml new file mode 100644 index 0000000000..f0ef0e33cc --- /dev/null +++ b/.github/workflows/homebrewpublish.yaml @@ -0,0 +1,17 @@ +name: Publish to Homebrew + +on: + push: + tags: + - 'v*' +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Update Homebrew formula + uses: dawidd6/action-homebrew-bump-formula@v3 + with: + token: ${{secrets.PERSONAL_ACCESS_TOKEN}} + formula: commitizen From 3b8b82922cce1ef9eaa73a523bf4c6ac2bb884c1 Mon Sep 17 00:00:00 2001 From: Marcos Santiago <marcos@santiago.tv.br> Date: Thu, 12 Nov 2020 18:26:56 +0100 Subject: [PATCH 267/427] feat(bump): add flag `--local-version` that supports bumping only the local version instead of the public --- commitizen/bump.py | 21 ++++++++++++++++----- commitizen/cli.py | 5 +++++ commitizen/commands/bump.py | 10 +++++++--- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index e4120eb5b1..32f0944a77 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -108,7 +108,10 @@ def semver_generator(current_version: str, increment: str = None) -> str: def generate_version( - current_version: str, increment: str, prerelease: Optional[str] = None + current_version: str, + increment: str, + prerelease: Optional[str] = None, + is_local_version: bool = False, ) -> Version: """Based on the given increment a proper semver will be generated. @@ -122,10 +125,18 @@ def generate_version( MAJOR 1.0.0 -> 2.0.0 """ pre_version = prerelease_generator(current_version, prerelease=prerelease) - semver = semver_generator(current_version, increment=increment) - # TODO: post version - # TODO: dev version - return Version(f"{semver}{pre_version}") + + if is_local_version: + version = Version(current_version) + local_semver = semver_generator(str(version.local), increment=increment) + + return Version(f"{version.public}+{local_semver}{pre_version}") + else: + semver = semver_generator(current_version, increment=increment) + + # TODO: post version + # TODO: dev version + return Version(f"{semver}{pre_version}") def update_version_in_files( diff --git a/commitizen/cli.py b/commitizen/cli.py index d09ba76d20..2f847ef8cd 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -81,6 +81,11 @@ "action": "store_true", "help": "bump version in the files from the config", }, + { + "name": "--local-version", + "action": "store_true", + "help": "bump only the local version portion", + }, { "name": ["--changelog", "-ch"], "action": "store_true", diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 6a57fdb867..6a723daf1e 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -92,6 +92,7 @@ def __call__(self): # noqa: C901 increment: Optional[str] = self.arguments["increment"] prerelease: str = self.arguments["prerelease"] is_files_only: Optional[bool] = self.arguments["files_only"] + is_local_version: Optional[bool] = self.arguments["local_version"] current_tag_version: str = bump.create_tag( current_version, tag_format=tag_format @@ -117,7 +118,10 @@ def __call__(self): # noqa: C901 increment = None new_version = bump.generate_version( - current_version, increment, prerelease=prerelease + current_version, + increment, + prerelease=prerelease, + is_local_version=is_local_version, ) new_tag_version = bump.create_tag(new_version, tag_format=tag_format) message = bump.create_commit_message( @@ -140,7 +144,7 @@ def __call__(self): # noqa: C901 bump.update_version_in_files( current_version, - new_version.public, + str(new_version), version_files, check_consistency=self.check_consistency, ) @@ -159,7 +163,7 @@ def __call__(self): # noqa: C901 changelog_cmd() c = cmd.run(f"git add {changelog_cmd.file_name}") - self.config.set_key("version", new_version.public) + self.config.set_key("version", str(new_version)) c = git.commit(message, args=self._get_commit_args()) if c.return_code != 0: raise BumpCommitFailedError(f'git.commit error: "{c.err.strip()}"') From 42e43616b5448c2eda0a4cb39aa2944f8a6df12b Mon Sep 17 00:00:00 2001 From: Marcos Santiago <marcos@santiago.tv.br> Date: Fri, 13 Nov 2020 16:30:36 +0100 Subject: [PATCH 268/427] test(bump): add missing tests for local-version flag --- commitizen/bump.py | 10 +++++----- tests/commands/test_bump_command.py | 21 +++++++++++++++++++++ tests/test_bump_create_tag.py | 3 +++ tests/test_bump_find_version.py | 22 ++++++++++++++++++++++ 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index 32f0944a77..ccb1257e7d 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -124,14 +124,14 @@ def generate_version( MINOR 1.0.0 -> 1.1.0 MAJOR 1.0.0 -> 2.0.0 """ - pre_version = prerelease_generator(current_version, prerelease=prerelease) - if is_local_version: version = Version(current_version) - local_semver = semver_generator(str(version.local), increment=increment) + pre_version = prerelease_generator(str(version.local), prerelease=prerelease) + semver = semver_generator(str(version.local), increment=increment) - return Version(f"{version.public}+{local_semver}{pre_version}") + return Version(f"{version.public}+{semver}{pre_version}") else: + pre_version = prerelease_generator(current_version, prerelease=prerelease) semver = semver_generator(current_version, increment=increment) # TODO: post version @@ -199,7 +199,7 @@ def create_tag(version: Union[Version, str], tag_format: Optional[str] = None): version = Version(version) if not tag_format: - return version.public + return str(version) major, minor, patch = version.release prerelease = "" diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index ce19c136bc..6818ddda09 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -243,6 +243,27 @@ def test_bump_files_only(mocker, tmp_commitizen_project): assert "0.3.0" in f.read() +def test_bump_local_version(mocker, tmp_commitizen_project): + tmp_version_file = tmp_commitizen_project.join("__version__.py") + tmp_version_file.write("4.5.1+0.1.0") + tmp_commitizen_cfg_file = tmp_commitizen_project.join("pyproject.toml") + tmp_commitizen_cfg_file.write( + f"[tool.commitizen]\n" + 'version="4.5.1+0.1.0"\n' + f'version_files = ["{str(tmp_version_file)}"]' + ) + + create_file_and_commit("feat: new user interface") + testargs = ["cz", "bump", "--yes", "--local-version"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + tag_exists = git.tag_exist("4.5.1+0.2.0") + assert tag_exists is True + + with open(tmp_version_file, "r") as f: + assert "4.5.1+0.2.0" in f.read() + + def test_bump_dry_run(mocker, capsys, tmp_commitizen_project): create_file_and_commit("feat: new file") diff --git a/tests/test_bump_create_tag.py b/tests/test_bump_create_tag.py index b6e06bcf51..0d6ee60d69 100644 --- a/tests/test_bump_create_tag.py +++ b/tests/test_bump_create_tag.py @@ -10,6 +10,9 @@ (("1.2.3", "ver$major.$minor.$patch"), "ver1.2.3"), (("1.2.3a0", "ver$major.$minor.$patch.$prerelease"), "ver1.2.3.a0"), (("1.2.3rc2", "$major.$minor.$patch.$prerelease-majestic"), "1.2.3.rc2-majestic"), + (("1.2.3+1.0.0", "v$version"), "v1.2.3+1.0.0"), + (("1.2.3+1.0.0", "v$version-local"), "v1.2.3+1.0.0-local"), + (("1.2.3+1.0.0", "ver$major.$minor.$patch"), "ver1.2.3"), ] diff --git a/tests/test_bump_find_version.py b/tests/test_bump_find_version.py index ca1a6b57d5..1436d9bd1e 100644 --- a/tests/test_bump_find_version.py +++ b/tests/test_bump_find_version.py @@ -30,6 +30,12 @@ (("1.2.1", "MAJOR", None), "2.0.0"), ] +local_versions = [ + (("4.5.0+0.1.0", "PATCH", None), "4.5.0+0.1.1"), + (("4.5.0+0.1.1", "MINOR", None), "4.5.0+0.2.0"), + (("4.5.0+0.2.0", "MAJOR", None), "4.5.0+1.0.0"), +] + # this cases should be handled gracefully unexpected_cases = [ (("0.1.1rc0", None, "alpha"), "0.1.1a0"), @@ -73,3 +79,19 @@ def test_generate_version(test_input, expected): assert generate_version( current_version, increment=increment, prerelease=prerelease ) == Version(expected) + + +@pytest.mark.parametrize( + "test_input,expected", itertools.chain(local_versions), +) +def test_generate_version_local(test_input, expected): + current_version = test_input[0] + increment = test_input[1] + prerelease = test_input[2] + is_local_version = True + assert generate_version( + current_version, + increment=increment, + prerelease=prerelease, + is_local_version=is_local_version, + ) == Version(expected) From a651ec1fdc60e392c32072f541832ef28bc5d51d Mon Sep 17 00:00:00 2001 From: Marcos Santiago <marcos@santiago.tv.br> Date: Fri, 13 Nov 2020 17:31:28 +0100 Subject: [PATCH 269/427] docs(bump): update bump documentation --- docs/bump.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/bump.md b/docs/bump.md index 3ff2d6a286..2abdb2b687 100644 --- a/docs/bump.md +++ b/docs/bump.md @@ -54,7 +54,7 @@ Some examples: ```bash $ cz bump --help -usage: cz bump [-h] [--dry-run] [--files-only] [--changelog] [--no-verify] +usage: cz bump [-h] [--dry-run] [--files-only] [--changelog] [--no-verify] [--local-version] [--yes] [--tag-format TAG_FORMAT] [--bump-message BUMP_MESSAGE] [--prerelease {alpha,beta,rc}] [--increment {MAJOR,MINOR,PATCH}] [--check-consistency] @@ -67,6 +67,7 @@ optional arguments: --no-verify this option bypasses the pre-commit and commit-msg hooks --yes accept automatically questions done + --local-version bump the local portion of the version --tag-format TAG_FORMAT the format used to tag the commit and read it, use it in existing projects, wrap around simple quotes @@ -131,6 +132,24 @@ However, it will still update `pyproject.toml` and `src/__version__.py`. To fix it, you'll first `git checkout .` to reset to the status before trying to bump and update the version in `setup.py` to `1.21.0` + +### `--local-version` + +Bump the local portion of the version. + +```bash +cz bump --local-version +``` + +For example, if we have `pyproject.toml` + +```toml +[tool.commitizen] +version = "5.3.5+0.1.0" +``` + +If `--local-version` is used, it will bump only the local version `0.1.0` and keep the public version `5.3.1` intact, bumping to the version `5.3.5+0.2.0`. + ## Configuration ### `tag_format` From 720befeedee70f2f9d8fbe4dbcddb41ff0f41ef9 Mon Sep 17 00:00:00 2001 From: Marcos Santiago <marcos@santiago.tv.br> Date: Sat, 14 Nov 2020 10:00:54 +0100 Subject: [PATCH 270/427] docs(bump): fix typo --- docs/bump.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/bump.md b/docs/bump.md index 2abdb2b687..25a2c10352 100644 --- a/docs/bump.md +++ b/docs/bump.md @@ -148,7 +148,7 @@ For example, if we have `pyproject.toml` version = "5.3.5+0.1.0" ``` -If `--local-version` is used, it will bump only the local version `0.1.0` and keep the public version `5.3.1` intact, bumping to the version `5.3.5+0.2.0`. +If `--local-version` is used, it will bump only the local version `0.1.0` and keep the public version `5.3.5` intact, bumping to the version `5.3.5+0.2.0`. ## Configuration From de44a0a5419721576fce48e16e4c74fdd5ddde11 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sat, 14 Nov 2020 10:02:49 +0000 Subject: [PATCH 271/427] =?UTF-8?q?bump:=20version=202.6.0=20=E2=86=92=202?= =?UTF-8?q?.7.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9613cd61a..c379afd5ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v2.7.0 (2020-11-14) + +### Feat + +- **bump**: add flag `--local-version` that supports bumping only the local version instead of the public + ## v2.6.0 (2020-11-04) ### Feat diff --git a/commitizen/__version__.py b/commitizen/__version__.py index e5e59e38da..2614ce9d96 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.6.0" +__version__ = "2.7.0" diff --git a/pyproject.toml b/pyproject.toml index 66157ab722..39f09b3f69 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.6.0" +version = "2.7.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.6.0" +version = "2.7.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From b5d8665cb5d2fab81756d9637777630abeaff1a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Omar=20Vergara=20P=C3=A9rez?= <daniel.omar.vergara@gmail.com> Date: Sat, 14 Nov 2020 15:32:58 -0600 Subject: [PATCH 272/427] feat(commitizen/cli): add the integration with argcomplete 137 --- commitizen/cli.py | 2 ++ pyproject.toml | 1 + 2 files changed, 3 insertions(+) diff --git a/commitizen/cli.py b/commitizen/cli.py index 2f847ef8cd..45aa33f303 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -3,6 +3,7 @@ import sys from functools import partial +import argcomplete from decli import cli from commitizen import commands, config @@ -265,6 +266,7 @@ def main(): conf = config.read_cfg() parser = cli(data) + argcomplete.autocomplete(parser) # Show help if no arg provided if len(sys.argv) == 1: parser.print_help(sys.stderr) diff --git a/pyproject.toml b/pyproject.toml index 39f09b3f69..9eadaf7fa7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,6 +53,7 @@ packaging = ">=19,<21" tomlkit = "^0.5.3" jinja2 = "^2.10.3" pyyaml = ">=3.08" +argcomplete = "^1.12.1" [tool.poetry.dev-dependencies] ipython = "^7.2" From bf56194d97c6785377ca82aa9266fc8e6cce7fec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Omar=20Vergara=20P=C3=A9rez?= <daniel.omar.vergara@gmail.com> Date: Sat, 14 Nov 2020 15:34:57 -0600 Subject: [PATCH 273/427] test(tests/test_cli): add a test function to test the activation of the auto-completion for cz 137 --- tests/test_cli.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/test_cli.py b/tests/test_cli.py index 7935806be2..59627f9d9b 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,4 +1,5 @@ import sys +import subprocess import pytest @@ -78,3 +79,16 @@ def test_commitizen_debug_excepthook(capsys): assert excinfo.type == SystemExit assert excinfo.value.code == NotAGitProjectError.exit_code assert "NotAGitProjectError" in str(excinfo.traceback[0]) + + +def test_argcomplete_activation(): + """ + This function is testing the one-time activation of argcomplete for + commitizen only. + + Equivalent to run: + $ eval "$(register-python-argcomplete pytest)" + """ + output = subprocess.run(["register-python-argcomplete", "cz"]) + + assert output.returncode == 0 From 61c13e451843b38e0980a563047e9a061670153a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Omar=20Vergara=20P=C3=A9rez?= <daniel.omar.vergara@gmail.com> Date: Sat, 14 Nov 2020 15:36:07 -0600 Subject: [PATCH 274/427] docs(docs/README): add the instructions to activate the auto-completion for cz in README.md 137 test(tests/test_cli): add a missing dependency 137 --- docs/README.md | 26 ++++++++++++++++++++++++++ tests/test_cli.py | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 4b87077126..77205dfc1a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -144,6 +144,32 @@ commands: current project (default: installed commitizen) ``` +## Setting up bash completion + +When using bash as your shell (limited support for zsh, fish, and tcsh is available), Commitizen can use [argcomplete](https://kislyuk.github.io/argcomplete/) for auto-completion. For this argcomplete needs to be enabled. + +argcomplete is installed when you install Commitizen since it's a dependency. + +If Commitizen is installed globally, global activation can be executed: + +```bash +sudo activate-global-python-argcomplete +``` + +For permanent (but not global) Commitizen activation, use: + +```bash +register-python-argcomplete cz >> ~/.bashrc +``` + +For one-time activation of argcomplete for Commitizen only, use: + +```bash +eval "$(register-python-argcomplete cz)" +``` + +For further information on activation, please visit the [argcomplete website](https://kislyuk.github.io/argcomplete/). + ## Third-Party Commitizen Templates See [Third-Party Commitizen Templates](third-party-commitizen.md). diff --git a/tests/test_cli.py b/tests/test_cli.py index 59627f9d9b..2b73bbd5cf 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,5 +1,5 @@ -import sys import subprocess +import sys import pytest From df3a87d3ad46b656484041f0d008bfbdf8f4a062 Mon Sep 17 00:00:00 2001 From: Marcos Santiago <marcos@santiago.tv.br> Date: Wed, 11 Nov 2020 14:55:10 +0100 Subject: [PATCH 275/427] feat: allow files-only to set config version and create changelog --- commitizen/commands/bump.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 6a723daf1e..f188c6ab40 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -148,8 +148,6 @@ def __call__(self): # noqa: C901 version_files, check_consistency=self.check_consistency, ) - if is_files_only: - raise ExpectedExit() if self.changelog: changelog_cmd = Changelog( @@ -164,6 +162,10 @@ def __call__(self): # noqa: C901 c = cmd.run(f"git add {changelog_cmd.file_name}") self.config.set_key("version", str(new_version)) + + if is_files_only: + raise ExpectedExit() + c = git.commit(message, args=self._get_commit_args()) if c.return_code != 0: raise BumpCommitFailedError(f'git.commit error: "{c.err.strip()}"') From 2a39747c7cbeab2b9ecebb4f55172edaa7920049 Mon Sep 17 00:00:00 2001 From: Marcos Santiago <marcos@santiago.tv.br> Date: Thu, 12 Nov 2020 11:41:46 +0100 Subject: [PATCH 276/427] test(bump_command): test if the version in the configuration file was updated when using the flag --- tests/commands/test_bump_command.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index 6818ddda09..806c930594 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -242,6 +242,9 @@ def test_bump_files_only(mocker, tmp_commitizen_project): with open(tmp_version_file, "r") as f: assert "0.3.0" in f.read() + with open(tmp_commitizen_cfg_file, "r") as f: + assert "0.3.0" in f.read() + def test_bump_local_version(mocker, tmp_commitizen_project): tmp_version_file = tmp_commitizen_project.join("__version__.py") From 71f34f79feea264a284db2ff3354aa59fb81b44b Mon Sep 17 00:00:00 2001 From: Marcos Santiago <marcos@santiago.tv.br> Date: Sat, 14 Nov 2020 13:44:23 +0100 Subject: [PATCH 277/427] docs(bump): add explanation for '--files-only' flag --- docs/bump.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/bump.md b/docs/bump.md index 25a2c10352..668120588d 100644 --- a/docs/bump.md +++ b/docs/bump.md @@ -83,6 +83,14 @@ optional arguments: configuration and version_files ``` +### `--files-only` + +Bumps the version in the files defined in `version_files` without creating a commit and tag on the git repository, + +```bash +cz bump --files-only +``` + ### `--changelog` Generate a **changelog** along with the new version and tag when bumping. From d42f744c3dd96aac568272f9d84e8000a22fc9ff Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sun, 15 Nov 2020 04:02:04 +0000 Subject: [PATCH 278/427] =?UTF-8?q?bump:=20version=202.7.0=20=E2=86=92=202?= =?UTF-8?q?.8.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c379afd5ed..bfdcb8c7ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v2.8.0 (2020-11-15) + +### Feat + +- allow files-only to set config version and create changelog + ## v2.7.0 (2020-11-14) ### Feat diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 2614ce9d96..892994aa6c 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.7.0" +__version__ = "2.8.0" diff --git a/pyproject.toml b/pyproject.toml index 39f09b3f69..1335c81e2d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.7.0" +version = "2.8.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.7.0" +version = "2.8.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 7bafa4211ae5aee2de70125cd6078a455454d553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 21 Nov 2020 14:53:42 +0100 Subject: [PATCH 279/427] fix: prevent prerelase from creating a bump when there are no commits Closes #281 --- commitizen/commands/bump.py | 14 ++++++++++++++ tests/commands/test_bump_command.py | 26 ++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index f188c6ab40..666e29535d 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -112,6 +112,19 @@ def __call__(self): # noqa: C901 if increment is None: increment = self.find_increment(commits) + # It may happen that there are commits, but they are not elegible + # for an increment, this generates a problem when using prerelease (#281) + if ( + prerelease + and increment is None + and not current_version_instance.is_prerelease + ): + raise NoCommitsFoundError( + "[NO_COMMITS_FOUND]\n" + "No commits found to generate a pre-release.\n" + "To avoid this error, manually specify the type of increment with `--increment`" + ) + # Increment is removed when current and next version # are expected to be prereleases. if prerelease and current_version_instance.is_prerelease: @@ -123,6 +136,7 @@ def __call__(self): # noqa: C901 prerelease=prerelease, is_local_version=is_local_version, ) + new_tag_version = bump.create_tag(new_version, tag_format=tag_format) message = bump.create_commit_message( current_version, new_version, bump_commit_message diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index 806c930594..77ea4840b0 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -358,3 +358,29 @@ def test_bump_with_changelog_config(mocker, changelog_path, config_path): out = f.read() assert out.startswith("#") assert "0.2.0" in out + + +def test_prevent_prerelease_when_no_increment_detected( + mocker, capsys, tmp_commitizen_project +): + create_file_and_commit("feat: new file") + + testargs = ["cz", "bump", "--yes"] + mocker.patch.object(sys, "argv", testargs) + + cli.main() + out, _ = capsys.readouterr() + + assert "0.2.0" in out + + create_file_and_commit("test: new file") + testargs = ["cz", "bump", "-pr", "beta"] + mocker.patch.object(sys, "argv", testargs) + + with pytest.raises(NoCommitsFoundError) as excinfo: + cli.main() + + expected_error_message = ( + "[NO_COMMITS_FOUND]\n" "No commits found to generate a pre-release." + ) + assert expected_error_message in str(excinfo.value) From ca4b9729ff150764ccdfa9bad96eb0f9f7e5cba2 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sat, 21 Nov 2020 15:14:52 +0000 Subject: [PATCH 280/427] =?UTF-8?q?bump:=20version=202.8.0=20=E2=86=92=202?= =?UTF-8?q?.8.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfdcb8c7ac..01d927d2c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v2.8.1 (2020-11-21) + +### Fix + +- prevent prerelase from creating a bump when there are no commits + ## v2.8.0 (2020-11-15) ### Feat diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 892994aa6c..b4066b65ab 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.8.0" +__version__ = "2.8.1" diff --git a/pyproject.toml b/pyproject.toml index 1335c81e2d..872fcd51a3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.8.0" +version = "2.8.1" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.8.0" +version = "2.8.1" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 5120d10463dfc9fdeb3121197db49b2b499e5317 Mon Sep 17 00:00:00 2001 From: Emiliano Dalla Verde Marcozzi <edvm@fedoraproject.org> Date: Sat, 21 Nov 2020 10:58:48 -0300 Subject: [PATCH 281/427] docs(README.md): adds missing link --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 4b87077126..85b8ee0ab1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -12,7 +12,7 @@ versions](https://img.shields.io/pypi/pyversions/commitizen.svg?style=flat-squar --- -**Documentation**: https://commitizen-tools.github.io/commitizen/ +**Documentation:** [https://commitizen-tools.github.io/commitizen/](https://commitizen-tools.github.io/commitizen/) --- From 8debb525ba22982800ab421120394b1313cc64ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 21 Nov 2020 18:01:00 +0100 Subject: [PATCH 282/427] fix: support `!` in cz check command Closes #283 --- commitizen/cz/conventional_commits/conventional_commits.py | 2 +- tests/commands/test_check_command.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index ba297f8ccb..7d5c27570c 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -178,7 +178,7 @@ def schema(self) -> str: def schema_pattern(self) -> str: PATTERN = ( - r"(build|ci|docs|feat|fix|perf|refactor|style|test|chore|revert|bump)" + r"(build|ci|docs|feat|fix|perf|refactor|style|test|chore|revert|bump)!?" r"(\(\S+\))?:(\s.*)" ) return PATTERN diff --git a/tests/commands/test_check_command.py b/tests/commands/test_check_command.py index 95eb007238..df54c1234e 100644 --- a/tests/commands/test_check_command.py +++ b/tests/commands/test_check_command.py @@ -44,6 +44,7 @@ 'Revert "fix(pre-commit): set pre-commit check stage to commit-msg"\n' "This reverts commit afc70133e4a81344928561fbf3bb20738dfc8a0b." ), + "feat!: add user stuff", ] From fe69da848604579c506e8ee6ef7f835cab4c7c00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 21 Nov 2020 18:07:40 +0100 Subject: [PATCH 283/427] docs: correct typos and outdated info Closes #288 --- docs/contributing.md | 2 +- docs/customization.md | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/contributing.md b/docs/contributing.md index 224aeb6442..4f04978a25 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -17,5 +17,5 @@ If you're a first-time contributor, you can check the issues with [good first is (We use [CodeCov](https://codecov.io/) to ensure our test coverage does not drop.) 7. Use [commitizen](https://github.com/commitizen-tools/commitizen) to do git commit. 8. Run `./scripts/format` and `./scripts/test` to ensure you follow the coding style and the tests pass. -9. Update `READMD.md` and `CHANGELOG.md` for your changes. +9. Update `README.md` and `CHANGELOG.md` for your changes. 10. Send a [pull request](https://github.com/commitizen-tools/commitizen/pulls) 🙏 diff --git a/docs/customization.md b/docs/customization.md index 2478bdc5f7..3f0c6b0149 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -48,17 +48,17 @@ message = "Do you want to add body message in commit?" ### Customize configuration -| Parameter | Type | Default | Description | -| ------------------ | ------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `questions` | `dict` | `None` | Questions regarding the commit message. Detailed below. | -| `message_template` | `str` | `None` | The template for generating message from the given answers. `message_template` should either follow 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`. | -| `schema_pattern` | `str` | `None` | (OPTIONAL) The regular expression used to do commit message validation. Used by `cz check`. | -| `info_path` | `str` | `None` | (OPTIONAL) The path to the file that contains explanation of the commit rules. Used by `cz info`. If not provided `cz info`, will load `info` instead. | -| `info` | `str` | `None` | (OPTIONAL) Explanation of the commit rules. Used by `cz info`. | -| `bump_map` | `dict` | `None` | (OPTIONAL) Dictionary mapping the extracted information to a `SemVer` increment type (`MAJOR`, `MINOR`, `PATCH`) | -| `bump_pattern` | `str` | `None` | (OPTIONAL) Regex to extract information from commit (subject and body) | +| Parameter | Type | Default | Description | +| ------------------ | ------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `questions` | `dict` | `None` | Questions regarding the commit message. Detailed below. | +| `message_template` | `str` | `None` | The template for generating message from the given answers. `message_template` should either follow [Jinja2](https://jinja.palletsprojects.com/en/2.10.x/) formatting specification, and all the variables in this template should be defined in `name` in `questions` | +| `example` | `str` | `None` | (OPTIONAL) Provide an example to help understand the style. Used by `cz example`. | +| `schema` | `str` | `None` | (OPTIONAL) Show the schema used. Used by `cz schema`. | +| `schema_pattern` | `str` | `None` | (OPTIONAL) The regular expression used to do commit message validation. Used by `cz check`. | +| `info_path` | `str` | `None` | (OPTIONAL) The path to the file that contains explanation of the commit rules. Used by `cz info`. If not provided `cz info`, will load `info` instead. | +| `info` | `str` | `None` | (OPTIONAL) Explanation of the commit rules. Used by `cz info`. | +| `bump_map` | `dict` | `None` | (OPTIONAL) Dictionary mapping the extracted information to a `SemVer` increment type (`MAJOR`, `MINOR`, `PATCH`) | +| `bump_pattern` | `str` | `None` | (OPTIONAL) Regex to extract information from commit (subject and body) | #### Detailed `questions` content From d98864aa9514c63baf3228a8b80d5339d5dd3942 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sat, 21 Nov 2020 17:08:51 +0000 Subject: [PATCH 284/427] =?UTF-8?q?bump:=20version=202.8.1=20=E2=86=92=202?= =?UTF-8?q?.8.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01d927d2c2..1cc2482180 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v2.8.2 (2020-11-21) + +### Fix + +- support `!` in cz check command + ## v2.8.1 (2020-11-21) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index b4066b65ab..239bf2b2bc 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.8.1" +__version__ = "2.8.2" diff --git a/pyproject.toml b/pyproject.toml index 872fcd51a3..7af90e3d74 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.8.1" +version = "2.8.2" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.8.1" +version = "2.8.2" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 58c5a92d9b3e07c66a36d68063d86f148d33444a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 21 Nov 2020 18:24:42 +0100 Subject: [PATCH 285/427] docs: inform about GITHUB_TOKEN vs PERSONAL_ACCESS_TOKEN in Github actions tutorial Closes #271 --- docs/tutorials/github_actions.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/tutorials/github_actions.md b/docs/tutorials/github_actions.md index 1c6494195f..aad2e8eb4f 100644 --- a/docs/tutorials/github_actions.md +++ b/docs/tutorials/github_actions.md @@ -11,6 +11,9 @@ project repository and then `Settings > Secrets > Add new secret`. 3. In your repository create a new file `.github/workflows/bumpversion.yml` with the following content. +!!! warning + If you use `GITHUB_TOKEN` instead of `PERSONAL_ACCESS_TOKEN`, the job won't trigger another workflow. It's like using `[skip ci]` in other CI's. + ```yaml name: Bump version From 5486075218367450d1c8b954601a17035e343b40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 21 Nov 2020 18:41:52 +0100 Subject: [PATCH 286/427] ci: trigger homebrew job only when publish was finished --- .github/workflows/homebrewpublish.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/homebrewpublish.yaml b/.github/workflows/homebrewpublish.yaml index f0ef0e33cc..fee4a70405 100644 --- a/.github/workflows/homebrewpublish.yaml +++ b/.github/workflows/homebrewpublish.yaml @@ -1,12 +1,15 @@ name: Publish to Homebrew on: - push: - tags: - - 'v*' + workflow_run: + workflows: ["Upload Python Package"] + types: + - completed + jobs: deploy: runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - name: Checkout uses: actions/checkout@v2 From 2da7390b9c2691a60fc1f5c7bb6f0afa3690948d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Omar=20Vergara=20P=C3=A9rez?= <daniel.omar.vergara@gmail.com> Date: Fri, 27 Nov 2020 00:24:29 -0600 Subject: [PATCH 287/427] feat(commitizen/config/json_config): add json support for configuration 120 --- commitizen/config/__init__.py | 7 ++++- commitizen/config/json_config.py | 48 ++++++++++++++++++++++++++++++++ commitizen/defaults.py | 2 +- 3 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 commitizen/config/json_config.py diff --git a/commitizen/config/__init__.py b/commitizen/config/__init__.py index cf7af9311b..ed9c090013 100644 --- a/commitizen/config/__init__.py +++ b/commitizen/config/__init__.py @@ -1,8 +1,10 @@ from pathlib import Path +from typing import Union from commitizen import defaults, git from .base_config import BaseConfig +from .json_config import JsonConfig from .toml_config import TomlConfig @@ -26,10 +28,13 @@ def read_cfg() -> BaseConfig: with open(filename, "r") as f: data: str = f.read() - _conf: TomlConfig + _conf: Union[TomlConfig, JsonConfig] if "toml" in filename.suffix: _conf = TomlConfig(data=data, path=filename) + if "json" in filename.suffix: + _conf = JsonConfig(data=data, path=filename) + if _conf.is_empty_config: continue else: diff --git a/commitizen/config/json_config.py b/commitizen/config/json_config.py new file mode 100644 index 0000000000..37ce0f9d42 --- /dev/null +++ b/commitizen/config/json_config.py @@ -0,0 +1,48 @@ +import json +from pathlib import Path +from typing import Union + +from .base_config import BaseConfig + + +class JsonConfig(BaseConfig): + def __init__(self, *, data: str, path: Union[Path, str]): + super(JsonConfig, self).__init__() + self.is_empty_config = False + self._parse_setting(data) + self.add_path(path) + + def init_empty_config_content(self): + with open(self.path, "a") as json_file: + json.dump({"commitizen": ""}, json_file) + + def set_key(self, key, value): + """Set or update a key in the conf. + + For now only strings are supported. + We use to update the version number. + """ + with open(self.path, "r") as f: + parser = json.load(f) + + parser["commitizen"][key] = value + with open(self.path, "w") as f: + json.dump(parser, f) + return self + + def _parse_setting(self, data: str): + """We expect to have a section in .cz.json looking like + + ``` + { + "commitizen": { + "name": "cz_conventional_commits" + } + } + ``` + """ + doc = json.loads(data) + try: + self.settings.update(doc["commitizen"]) + except KeyError: + self.is_empty_config = True diff --git a/commitizen/defaults.py b/commitizen/defaults.py index 4f63c99d91..a0dfbb8668 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -2,7 +2,7 @@ from typing import Any, Dict, List name: str = "cz_conventional_commits" -config_files: List[str] = ["pyproject.toml", ".cz.toml"] +config_files: List[str] = ["pyproject.toml", ".cz.toml", ".cz.json", "cz.json"] DEFAULT_SETTINGS: Dict[str, Any] = { "name": "cz_conventional_commits", From d3ccd79033b1d3ea3f47c1001e2dd0cd5a29a43f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Omar=20Vergara=20P=C3=A9rez?= <daniel.omar.vergara@gmail.com> Date: Fri, 27 Nov 2020 00:25:47 -0600 Subject: [PATCH 288/427] test(tests/test_config): add support to run test for json config 120 --- tests/test_conf.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/test_conf.py b/tests/test_conf.py index 919fb46e78..6d40a42db4 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -1,3 +1,4 @@ +import json import os from pathlib import Path @@ -23,6 +24,14 @@ target-version = ['py36', 'py37', 'py38'] """ +JSON_CONFIG = { + "commitizen": { + "name": "cz_jira", + "version": "1.0.0", + "version_files": ["commitizen/__version__.py", "pyproject.toml"], + "style": [["pointer", "reverse"], ["question", "underline"]], + } +} _settings = { "name": "cz_jira", @@ -66,6 +75,8 @@ def config_files_manager(request, tmpdir): with open(filename, "w") as f: if "toml" in filename: f.write(PYPROJECT) + if "json" in filename: + json.dump(JSON_CONFIG, f) yield @@ -129,3 +140,13 @@ def test_init_empty_config_content_with_existing_content(self, tmpdir): with open(path, "r") as toml_file: assert toml_file.read() == existing_content + "[tool.commitizen]" + + +class TestJsonConfig: + def test_init_empty_config_content(self, tmpdir): + path = tmpdir.mkdir("commitizen").join(".cz.json") + json_config = config.JsonConfig(data="{}", path=path) + json_config.init_empty_config_content() + + with open(path, "r") as json_file: + assert json.load(json_file) == {"commitizen": ""} From 61a06f2a9e7a7d0bf0c74b2bb8846fb66afcbc1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Omar=20Vergara=20P=C3=A9rez?= <daniel.omar.vergara@gmail.com> Date: Fri, 27 Nov 2020 00:26:47 -0600 Subject: [PATCH 289/427] docs(dosc/config): add instructions on how to define a json config file 120 --- docs/config.md | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/docs/config.md b/docs/config.md index b27fda0ce6..bff8112eac 100644 --- a/docs/config.md +++ b/docs/config.md @@ -28,6 +28,65 @@ style = [ `.cz.toml` is recommended for **other languages** projects (js, go, etc). +## .cz.json or cz.json + +JSON may be a more commong configuration format for non-python projects, so Commitizen supports JSON config files, now. + +```json +{ + "commitizen": { + "name": "cz_conventional_commits", + "version": "0.1.0", + "version_files": [ + "src/__version__.py", + "pyproject.toml:version" + ], + "style": [ + [ + "qmark", + "fg:#ff9d00 bold" + ], + [ + "question", + "bold" + ], + [ + "answer", + "fg:#ff9d00 bold" + ], + [ + "pointer", + "fg:#ff9d00 bold" + ], + [ + "highlighted", + "fg:#ff9d00 bold" + ], + [ + "selected", + "fg:#cc5454" + ], + [ + "separator", + "fg:#cc5454" + ], + [ + "instruction", + "" + ], + [ + "text", + "" + ], + [ + "disabled", + "fg:#858585 italic" + ] + ] + } +} +``` + ## Settings | Variable | Type | Default | Description | From 33bfe1d7d6936a22221f9a85eca569389984b4a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Omar=20Vergara=20P=C3=A9rez?= <daniel.omar.vergara@gmail.com> Date: Sun, 29 Nov 2020 02:49:21 -0600 Subject: [PATCH 290/427] test(test_cs_customize): add support for testing customization for JsonConfig class 120 --- tests/test_cz_customize.py | 182 +++++++++++++++++++++++++++++++------ 1 file changed, 153 insertions(+), 29 deletions(-) diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py index 2cf0a5917d..d74814087e 100644 --- a/tests/test_cz_customize.py +++ b/tests/test_cz_customize.py @@ -1,13 +1,10 @@ import pytest -from commitizen.config import BaseConfig, TomlConfig +from commitizen.config import BaseConfig, JsonConfig, TomlConfig from commitizen.cz.customize import CustomizeCommitsCz from commitizen.exceptions import MissingCzCustomizeConfigError - -@pytest.fixture(scope="module") -def config(): - toml_str = r""" +TOML_STR = r""" [tool.commitizen.customize] message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" example = "feature: this feature enable customize through config file" @@ -36,8 +33,154 @@ def config(): type = "confirm" name = "show_message" message = "Do you want to add body message in commit?" +""" + +JSON_STR = r""" + { + "commitizen": { + "name": "cz_jira", + "version": "1.0.0", + "version_files": [ + "commitizen/__version__.py", + "pyproject.toml" + ], + "customize": { + "message_template": "{{change_type}}:{% if show_message %} {{message}}{% endif %}", + "example": "feature: this feature enable customize through config file", + "schema": "<type>: <body>", + "schema_pattern": "(feature|bug fix):(\\s.*)", + "bump_pattern": "^(break|new|fix|hotfix)", + "bump_map": { + "break": "MAJOR", + "new": "MINOR", + "fix": "PATCH", + "hotfix": "PATCH" + }, + "info": "This is a customized cz.", + "questions": [ + { + "type": "list", + "name": "change_type", + "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." + }, + { + "type": "confirm", + "name": "show_message", + "message": "Do you want to add body message in commit?" + } + ] + } + } + } +""" + +TOML_STR_INFO_PATH = """ + [tool.commitizen.customize] + message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" + example = "feature: this feature enable customize through config file" + schema = "<type>: <body>" + bump_pattern = "^(break|new|fix|hotfix)" + bump_map = {"break" = "MAJOR", "new" = "MINOR", "fix" = "PATCH", "hotfix" = "PATCH"} + info_path = "info.txt" +""" + +JSON_STR_INFO_PATH = r""" + { + "commitizen": { + "customize": { + "message_template": "{{change_type}}:{% if show_message %} {{message}}{% endif %}", + "example": "feature: this feature enable customize through config file", + "schema": "<type>: <body>", + "bump_pattern": "^(break|new|fix|hotfix)", + "bump_map": { + "break": "MAJOR", + "new": "MINOR", + "fix": "PATCH", + "hotfix": "PATCH" + }, + "info_path": "info.txt" + } + } + } +""" + +TOML_STR_WITHOUT_INFO = """ + [tool.commitizen.customize] + message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" + example = "feature: this feature enable customize through config file" + schema = "<type>: <body>" + bump_pattern = "^(break|new|fix|hotfix)" + bump_map = {"break" = "MAJOR", "new" = "MINOR", "fix" = "PATCH", "hotfix" = "PATCH"} +""" + +JSON_STR_WITHOUT_PATH = r""" + { + "commitizen": { + "customize": { + "message_template": "{{change_type}}:{% if show_message %} {{message}}{% endif %}", + "example": "feature: this feature enable customize through config file", + "schema": "<type>: <body>", + "bump_pattern": "^(break|new|fix|hotfix)", + "bump_map": { + "break": "MAJOR", + "new": "MINOR", + "fix": "PATCH", + "hotfix": "PATCH" + } + } + } + } +""" + + +@pytest.fixture( + params=[ + TomlConfig(data=TOML_STR, path="not_exist.toml"), + JsonConfig(data=JSON_STR, path="not_exist.json"), + ] +) +def config(request): + """Parametrize the config fixture + + This fixture allow to test multiple config formats, + without add the builtin parametrize decorator """ - return TomlConfig(data=toml_str, path="not_exist.toml") + return request.param + + +@pytest.fixture( + params=[ + TomlConfig(data=TOML_STR_INFO_PATH, path="not_exist.toml"), + JsonConfig(data=JSON_STR_INFO_PATH, path="not_exist.json"), + ] +) +def config_info(request): + return request.param + + +@pytest.fixture( + params=[ + TomlConfig(data=TOML_STR_WITHOUT_INFO, path="not_exist.toml"), + JsonConfig(data=JSON_STR_WITHOUT_PATH, path="not_exist.json"), + ] +) +def config_without_info(request): + return request.param def test_initialize_cz_customize_failed(): @@ -126,34 +269,15 @@ def test_info(config): assert "This is a customized cz." in cz.info() -def test_info_with_info_path(tmpdir): +def test_info_with_info_path(tmpdir, config_info): with tmpdir.as_cwd(): tmpfile = tmpdir.join("info.txt") tmpfile.write("Test info") - toml_str = """ - [tool.commitizen.customize] - message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" - example = "feature: this feature enable customize through config file" - schema = "<type>: <body>" - bump_pattern = "^(break|new|fix|hotfix)" - bump_map = {"break" = "MAJOR", "new" = "MINOR", "fix" = "PATCH", "hotfix" = "PATCH"} - info_path = "info.txt" - """ - config = TomlConfig(data=toml_str, path="not_exist.toml") - cz = CustomizeCommitsCz(config) + cz = CustomizeCommitsCz(config_info) assert "Test info" in cz.info() -def test_info_without_info(): - toml_str = """ - [tool.commitizen.customize] - message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" - example = "feature: this feature enable customize through config file" - schema = "<type>: <body>" - bump_pattern = "^(break|new|fix|hotfix)" - bump_map = {"break" = "MAJOR", "new" = "MINOR", "fix" = "PATCH", "hotfix" = "PATCH"} - """ - config = TomlConfig(data=toml_str, path="not_exist.toml") - cz = CustomizeCommitsCz(config) +def test_info_without_info(config_without_info): + cz = CustomizeCommitsCz(config_without_info) assert cz.info() is None From 987107aa22a0df7396be37d7ccb86746bf3e9529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Omar=20Vergara=20P=C3=A9rez?= <daniel.omar.vergara@gmail.com> Date: Sun, 29 Nov 2020 03:06:30 -0600 Subject: [PATCH 291/427] docs(customization): add a json config file as a example for the new implementation 120 --- docs/customization.md | 54 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/docs/customization.md b/docs/customization.md index 3f0c6b0149..06e084a758 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -3,7 +3,7 @@ We have two different ways to do so. ## 1. Customize in configuration file -**This is only supported when configuring through `toml` (e.g., `pyproject.toml`, `.cz`, and `.cz.toml`)** +**This is only supported when configuring through `toml` or `json` (e.g., `pyproject.toml`, `.cz.toml`, `.cz.toml`, `.cz.json`, and `cz.json`)** The basic steps are: @@ -46,6 +46,58 @@ name = "show_message" message = "Do you want to add body message in commit?" ``` +The equivalent example for a json config file: + +```json +{ + "commitizen": { + "name": "cz_customize", + "customize": { + "message_template": "{{change_type}}:{% if show_message %} {{message}}{% endif %}", + "example": "feature: this feature enable customize through config file", + "schema": "<type>: <body>", + "schema_pattern": "(feature|bug fix):(\\s.*)", + "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", + "questions": [ + { + "type": "list", + "name": "change_type", + "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." + }, + { + "type": "confirm", + "name": "show_message", + "message": "Do you want to add body message in commit?" + } + ] + } + } +} +``` + ### Customize configuration | Parameter | Type | Default | Description | From 58fc55ad3ea417af53dfb25c65a9e248d4b8e78b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Omar=20Vergara=20P=C3=A9rez?= <daniel.omar.vergara@gmail.com> Date: Tue, 1 Dec 2020 19:27:06 -0600 Subject: [PATCH 292/427] feat(Init): add the json config support as an option at Init 120 --- commitizen/commands/init.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/commitizen/commands/init.py b/commitizen/commands/init.py index 1bfb643f0e..94c0e142e7 100644 --- a/commitizen/commands/init.py +++ b/commitizen/commands/init.py @@ -6,7 +6,7 @@ from commitizen import cmd, factory, out from commitizen.__version__ import __version__ -from commitizen.config import BaseConfig, TomlConfig +from commitizen.config import BaseConfig, JsonConfig, TomlConfig from commitizen.cz import registry from commitizen.defaults import config_files from commitizen.exceptions import NoAnswersError @@ -26,6 +26,8 @@ def __call__(self): config_path = self._ask_config_path() if "toml" in config_path: self.config = TomlConfig(data="", path=config_path) + elif "json" in config_path: + self.config = JsonConfig(data="{}", path=config_path) self.config.init_empty_config_content() From cb91feacb1e03d6130656f64e3b7d5a652d40249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Omar=20Vergara=20P=C3=A9rez?= <daniel.omar.vergara@gmail.com> Date: Wed, 2 Dec 2020 00:27:44 -0600 Subject: [PATCH 293/427] fix(json_config): fix the emtpy_config_content method --- commitizen/config/json_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commitizen/config/json_config.py b/commitizen/config/json_config.py index 37ce0f9d42..fbf37bbd83 100644 --- a/commitizen/config/json_config.py +++ b/commitizen/config/json_config.py @@ -14,7 +14,7 @@ def __init__(self, *, data: str, path: Union[Path, str]): def init_empty_config_content(self): with open(self.path, "a") as json_file: - json.dump({"commitizen": ""}, json_file) + json.dump({"commitizen": {}}, json_file) def set_key(self, key, value): """Set or update a key in the conf. From 3d4a5496f59ac26ca6e555edbbe113cb2ab4041c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Omar=20Vergara=20P=C3=A9rez?= <daniel.omar.vergara@gmail.com> Date: Wed, 2 Dec 2020 00:32:19 -0600 Subject: [PATCH 294/427] test(test_init_command): test the json config behavior when the Init function is called --- tests/commands/test_init_command.py | 60 ++++++++++++++++++++--------- tests/test_conf.py | 2 +- 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/tests/commands/test_init_command.py b/tests/commands/test_init_command.py index 555e0d816c..432139695c 100644 --- a/tests/commands/test_init_command.py +++ b/tests/commands/test_init_command.py @@ -1,3 +1,4 @@ +import json import os import pytest @@ -30,6 +31,14 @@ def ask(self): 'tag_format = "$version"\n' ) +EXPECTED_JSON_CONFIG = { + "commitizen": { + "name": "cz_conventional_commits", + "version": "0.0.1", + "tag_format": "$version", + } +} + def test_init_without_setup_pre_commit_hook(tmpdir, mocker, config): mocker.patch( @@ -85,47 +94,54 @@ def test_init_without_choosing_tag(config, mocker, tmpdir): class TestPreCommitCases: - @pytest.fixture(scope="function", autouse=True) - def default_choices(_, mocker): + @pytest.fixture(scope="function", params=["pyproject.toml", ".cz.json"]) + def default_choice(_, request, mocker): mocker.patch( "questionary.select", side_effect=[ - FakeQuestion("pyproject.toml"), + FakeQuestion(request.param), FakeQuestion("cz_conventional_commits"), ], ) mocker.patch("questionary.confirm", return_value=FakeQuestion(True)) mocker.patch("questionary.text", return_value=FakeQuestion("$version")) mocker.patch("questionary.confirm", return_value=FakeQuestion(True)) + return request.param - def test_no_existing_pre_commit_conifg(_, tmpdir, config): + def test_no_existing_pre_commit_json_conifg(_, default_choice, tmpdir, config): with tmpdir.as_cwd(): commands.Init(config)() - with open("pyproject.toml", "r") as toml_file: - config_data = toml_file.read() - assert config_data == expected_config + with open(default_choice, "r") as file: + if "json" in default_choice: + assert json.load(file) == EXPECTED_JSON_CONFIG + else: + config_data = file.read() + assert config_data == expected_config with open(pre_commit_config_filename, "r") as pre_commit_file: pre_commit_config_data = yaml.safe_load(pre_commit_file.read()) assert pre_commit_config_data == {"repos": [cz_hook_config]} - def test_empty_pre_commit_config(_, tmpdir, config): + def test_empty_pre_commit_config(_, default_choice, tmpdir, config): with tmpdir.as_cwd(): p = tmpdir.join(pre_commit_config_filename) p.write("") commands.Init(config)() - with open("pyproject.toml", "r") as toml_file: - config_data = toml_file.read() - assert config_data == expected_config + with open(default_choice, "r") as file: + if "json" in default_choice: + assert json.load(file) == EXPECTED_JSON_CONFIG + else: + config_data = file.read() + assert config_data == expected_config with open(pre_commit_config_filename, "r") as pre_commit_file: pre_commit_config_data = yaml.safe_load(pre_commit_file.read()) assert pre_commit_config_data == {"repos": [cz_hook_config]} - def test_pre_commit_config_without_cz_hook(_, tmpdir, config): + def test_pre_commit_config_without_cz_hook(_, default_choice, tmpdir, config): existing_hook_config = { "repo": "https://github.com/pre-commit/pre-commit-hooks", "rev": "v1.2.3", @@ -138,9 +154,12 @@ def test_pre_commit_config_without_cz_hook(_, tmpdir, config): commands.Init(config)() - with open("pyproject.toml", "r") as toml_file: - config_data = toml_file.read() - assert config_data == expected_config + with open(default_choice, "r") as file: + if "json" in default_choice: + assert json.load(file) == EXPECTED_JSON_CONFIG + else: + config_data = file.read() + assert config_data == expected_config with open(pre_commit_config_filename, "r") as pre_commit_file: pre_commit_config_data = yaml.safe_load(pre_commit_file.read()) @@ -148,16 +167,19 @@ def test_pre_commit_config_without_cz_hook(_, tmpdir, config): "repos": [existing_hook_config, cz_hook_config] } - def test_cz_hook_exists_in_pre_commit_config(_, tmpdir, config): + def test_cz_hook_exists_in_pre_commit_config(_, default_choice, tmpdir, config): with tmpdir.as_cwd(): p = tmpdir.join(pre_commit_config_filename) p.write(yaml.safe_dump({"repos": [cz_hook_config]})) commands.Init(config)() - with open("pyproject.toml", "r") as toml_file: - config_data = toml_file.read() - assert config_data == expected_config + with open(default_choice, "r") as file: + if "json" in default_choice: + assert json.load(file) == EXPECTED_JSON_CONFIG + else: + config_data = file.read() + assert config_data == expected_config with open(pre_commit_config_filename, "r") as pre_commit_file: pre_commit_config_data = yaml.safe_load(pre_commit_file.read()) diff --git a/tests/test_conf.py b/tests/test_conf.py index 6d40a42db4..5ab66c2ff1 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -149,4 +149,4 @@ def test_init_empty_config_content(self, tmpdir): json_config.init_empty_config_content() with open(path, "r") as json_file: - assert json.load(json_file) == {"commitizen": ""} + assert json.load(json_file) == {"commitizen": {}} From e9321c5cf7aa294fd36997f32bdc493bb0d057b8 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 2 Dec 2020 08:41:17 +0000 Subject: [PATCH 295/427] =?UTF-8?q?bump:=20version=202.8.2=20=E2=86=92=202?= =?UTF-8?q?.9.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 11 +++++++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cc2482180..f66e4a76fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## v2.9.0 (2020-12-02) + +### Fix + +- **json_config**: fix the emtpy_config_content method + +### Feat + +- **Init**: add the json config support as an option at Init +- **commitizen/config/json_config**: add json support for configuration + ## v2.8.2 (2020-11-21) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 239bf2b2bc..43ce13db01 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.8.2" +__version__ = "2.9.0" diff --git a/pyproject.toml b/pyproject.toml index 7af90e3d74..528197a7ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.8.2" +version = "2.9.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.8.2" +version = "2.9.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 57fe0eaf52fbe625c11eb12a32a0dcf8791cba49 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 2 Dec 2020 15:40:07 +0000 Subject: [PATCH 296/427] =?UTF-8?q?bump:=20version=202.9.0=20=E2=86=92=202?= =?UTF-8?q?.10.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f66e4a76fb..8da4562f75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v2.10.0 (2020-12-02) + +### Feat + +- **commitizen/cli**: add the integration with argcomplete + ## v2.9.0 (2020-12-02) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 43ce13db01..1c622223ba 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.9.0" +__version__ = "2.10.0" diff --git a/pyproject.toml b/pyproject.toml index 9174c59cc7..a449b73281 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.9.0" +version = "2.10.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.9.0" +version = "2.10.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From c09f37777a9f0919f37b8e9a613790c8d056d202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Omar=20Vergara=20P=C3=A9rez?= <daniel.omar.vergara@gmail.com> Date: Tue, 8 Dec 2020 00:53:14 -0600 Subject: [PATCH 297/427] feat: add yaml as a config option 314 feat(config): add support for the new class YAMLConfig at the root of the confi internal package 314 test(test_config): add test support for the class YAMLConfig 314 fix(YAMLConfig): add a TypeError exception to handle in _parse_settings method feat(init): add support for yaml config file at init 314 test(tests): add test functions to test YAMLConfig class at init and customization 314 docs(docs): add instructions on how to define yaml config files 314 --- commitizen/commands/init.py | 4 +- commitizen/config/__init__.py | 9 ++-- commitizen/config/yaml_config.py | 47 +++++++++++++++++++ commitizen/defaults.py | 9 +++- docs/config.md | 35 ++++++++++++++- docs/customization.md | 35 +++++++++++++++ tests/commands/test_init_command.py | 22 ++++++--- tests/test_conf.py | 10 +++-- tests/test_cz_customize.py | 70 ++++++++++++++++++++++++++++- 9 files changed, 224 insertions(+), 17 deletions(-) create mode 100644 commitizen/config/yaml_config.py diff --git a/commitizen/commands/init.py b/commitizen/commands/init.py index 94c0e142e7..96b06f2080 100644 --- a/commitizen/commands/init.py +++ b/commitizen/commands/init.py @@ -6,7 +6,7 @@ from commitizen import cmd, factory, out from commitizen.__version__ import __version__ -from commitizen.config import BaseConfig, JsonConfig, TomlConfig +from commitizen.config import BaseConfig, JsonConfig, TomlConfig, YAMLConfig from commitizen.cz import registry from commitizen.defaults import config_files from commitizen.exceptions import NoAnswersError @@ -28,6 +28,8 @@ def __call__(self): self.config = TomlConfig(data="", path=config_path) elif "json" in config_path: self.config = JsonConfig(data="{}", path=config_path) + elif "yaml" in config_path: + self.config = YAMLConfig(data="", path=config_path) self.config.init_empty_config_content() diff --git a/commitizen/config/__init__.py b/commitizen/config/__init__.py index ed9c090013..2cbd544825 100644 --- a/commitizen/config/__init__.py +++ b/commitizen/config/__init__.py @@ -6,6 +6,7 @@ from .base_config import BaseConfig from .json_config import JsonConfig from .toml_config import TomlConfig +from .yaml_config import YAMLConfig def read_cfg() -> BaseConfig: @@ -25,15 +26,17 @@ def read_cfg() -> BaseConfig: if not filename.exists(): continue + _conf: Union[TomlConfig, JsonConfig, YAMLConfig] + with open(filename, "r") as f: data: str = f.read() - _conf: Union[TomlConfig, JsonConfig] if "toml" in filename.suffix: _conf = TomlConfig(data=data, path=filename) - - if "json" in filename.suffix: + elif "json" in filename.suffix: _conf = JsonConfig(data=data, path=filename) + elif "yaml" in filename.suffix: + _conf = YAMLConfig(data=data, path=filename) if _conf.is_empty_config: continue diff --git a/commitizen/config/yaml_config.py b/commitizen/config/yaml_config.py new file mode 100644 index 0000000000..cc6c5f0338 --- /dev/null +++ b/commitizen/config/yaml_config.py @@ -0,0 +1,47 @@ +from pathlib import Path +from typing import Union + +import yaml + +from .base_config import BaseConfig + + +class YAMLConfig(BaseConfig): + def __init__(self, *, data: str, path: Union[Path, str]): + super(YAMLConfig, self).__init__() + self.is_empty_config = False + self._parse_setting(data) + self.add_path(path) + + def init_empty_config_content(self): + with open(self.path, "a") as json_file: + yaml.dump({"commitizen": {}}, json_file) + + def _parse_setting(self, data: str): + """We expect to have a section in cz.yaml looking like + + ``` + commitizen: + name: cz_conventional_commits + ``` + """ + doc = yaml.safe_load(data) + try: + self.settings.update(doc["commitizen"]) + except (KeyError, TypeError): + self.is_empty_config = True + + def set_key(self, key, value): + """Set or update a key in the conf. + + For now only strings are supported. + We use to update the version number. + """ + with open(self.path, "r") as yaml_file: + parser = yaml.load(yaml_file) + + parser["commitizen"][key] = value + with open(self.path, "w") as yaml_file: + yaml.dump(parser, yaml_file) + + return self diff --git a/commitizen/defaults.py b/commitizen/defaults.py index a0dfbb8668..c5f07992f6 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -2,7 +2,14 @@ from typing import Any, Dict, List name: str = "cz_conventional_commits" -config_files: List[str] = ["pyproject.toml", ".cz.toml", ".cz.json", "cz.json"] +config_files: List[str] = [ + "pyproject.toml", + ".cz.toml", + ".cz.json", + "cz.json", + ".cz.yaml", + "cz.yaml", +] DEFAULT_SETTINGS: Dict[str, Any] = { "name": "cz_conventional_commits", diff --git a/docs/config.md b/docs/config.md index bff8112eac..204edcf887 100644 --- a/docs/config.md +++ b/docs/config.md @@ -30,7 +30,7 @@ style = [ ## .cz.json or cz.json -JSON may be a more commong configuration format for non-python projects, so Commitizen supports JSON config files, now. +JSON might be a more common configuration format for non-python projects, so Commitizen supports JSON config files, now. ```json { @@ -87,6 +87,39 @@ JSON may be a more commong configuration format for non-python projects, so Comm } ``` +## .cz.yaml or cz.yaml +YAML is another format for **non-python** proyects as well, supported by Commitizen: + +```yaml +commitizen: + name: cz_conventional_commits + version: 0.1.0 + version_files: + - src/__version__.py + - pyproject.toml:version + style: + - - qmark + - fg:#ff9d00 bold + - - question + - bold + - - answer + - fg:#ff9d00 bold + - - pointer + - fg:#ff9d00 bold + - - highlighted + - fg:#ff9d00 bold + - - selected + - fg:#cc5454 + - - separator + - fg:#cc5454 + - - instruction + - '' + - - text + - '' + - - disabled + - fg:#858585 italic +``` + ## Settings | Variable | Type | Default | Description | diff --git a/docs/customization.md b/docs/customization.md index 06e084a758..0d86dc057f 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -98,6 +98,41 @@ The equivalent example for a json config file: } ``` +And the correspondent example for a yaml json file: + +```yaml +commitizen: + name: cz_customize + customize: + message_template: "{{change_type}}:{% if show_message %} {{message}}{% endif %}" + example: 'feature: this feature enable customize through config file' + schema: "<type>: <body>" + schema_pattern: "(feature|bug fix):(\\s.*)" + 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 + questions: + - type: list + name: change_type + 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. + - type: confirm + name: show_message + message: Do you want to add body message in commit? +``` + ### Customize configuration | Parameter | Type | Default | Description | diff --git a/tests/commands/test_init_command.py b/tests/commands/test_init_command.py index 432139695c..977e9e6a11 100644 --- a/tests/commands/test_init_command.py +++ b/tests/commands/test_init_command.py @@ -31,7 +31,7 @@ def ask(self): 'tag_format = "$version"\n' ) -EXPECTED_JSON_CONFIG = { +EXPECTED_DICT_CONFIG = { "commitizen": { "name": "cz_conventional_commits", "version": "0.0.1", @@ -94,7 +94,7 @@ def test_init_without_choosing_tag(config, mocker, tmpdir): class TestPreCommitCases: - @pytest.fixture(scope="function", params=["pyproject.toml", ".cz.json"]) + @pytest.fixture(scope="function", params=["pyproject.toml", ".cz.json", ".cz.yaml"]) def default_choice(_, request, mocker): mocker.patch( "questionary.select", @@ -108,13 +108,15 @@ def default_choice(_, request, mocker): mocker.patch("questionary.confirm", return_value=FakeQuestion(True)) return request.param - def test_no_existing_pre_commit_json_conifg(_, default_choice, tmpdir, config): + def test_no_existing_pre_commit_conifg(_, default_choice, tmpdir, config): with tmpdir.as_cwd(): commands.Init(config)() with open(default_choice, "r") as file: if "json" in default_choice: - assert json.load(file) == EXPECTED_JSON_CONFIG + assert json.load(file) == EXPECTED_DICT_CONFIG + elif "yaml" in default_choice: + assert yaml.load(file) == EXPECTED_DICT_CONFIG else: config_data = file.read() assert config_data == expected_config @@ -132,7 +134,9 @@ def test_empty_pre_commit_config(_, default_choice, tmpdir, config): with open(default_choice, "r") as file: if "json" in default_choice: - assert json.load(file) == EXPECTED_JSON_CONFIG + assert json.load(file) == EXPECTED_DICT_CONFIG + elif "yaml" in default_choice: + assert yaml.load(file) == EXPECTED_DICT_CONFIG else: config_data = file.read() assert config_data == expected_config @@ -156,7 +160,9 @@ def test_pre_commit_config_without_cz_hook(_, default_choice, tmpdir, config): with open(default_choice, "r") as file: if "json" in default_choice: - assert json.load(file) == EXPECTED_JSON_CONFIG + assert json.load(file) == EXPECTED_DICT_CONFIG + elif "yaml" in default_choice: + assert yaml.load(file) == EXPECTED_DICT_CONFIG else: config_data = file.read() assert config_data == expected_config @@ -176,7 +182,9 @@ def test_cz_hook_exists_in_pre_commit_config(_, default_choice, tmpdir, config): with open(default_choice, "r") as file: if "json" in default_choice: - assert json.load(file) == EXPECTED_JSON_CONFIG + assert json.load(file) == EXPECTED_DICT_CONFIG + elif "yaml" in default_choice: + assert yaml.load(file) == EXPECTED_DICT_CONFIG else: config_data = file.read() assert config_data == expected_config diff --git a/tests/test_conf.py b/tests/test_conf.py index 5ab66c2ff1..ea7b3a3c98 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -3,6 +3,7 @@ from pathlib import Path import pytest +import yaml from commitizen import config, defaults, git @@ -24,7 +25,7 @@ target-version = ['py36', 'py37', 'py38'] """ -JSON_CONFIG = { +DICT_CONFIG = { "commitizen": { "name": "cz_jira", "version": "1.0.0", @@ -33,6 +34,7 @@ } } + _settings = { "name": "cz_jira", "version": "1.0.0", @@ -75,8 +77,10 @@ def config_files_manager(request, tmpdir): with open(filename, "w") as f: if "toml" in filename: f.write(PYPROJECT) - if "json" in filename: - json.dump(JSON_CONFIG, f) + elif "json" in filename: + json.dump(DICT_CONFIG, f) + elif "yaml" in filename: + yaml.dump(DICT_CONFIG, f) yield diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py index d74814087e..479fcef7c4 100644 --- a/tests/test_cz_customize.py +++ b/tests/test_cz_customize.py @@ -1,6 +1,6 @@ import pytest -from commitizen.config import BaseConfig, JsonConfig, TomlConfig +from commitizen.config import BaseConfig, JsonConfig, TomlConfig, YAMLConfig from commitizen.cz.customize import CustomizeCommitsCz from commitizen.exceptions import MissingCzCustomizeConfigError @@ -89,6 +89,43 @@ } """ +YAML_STR = """ +commitizen: + name: cz_jira + version: 1.0.0 + version_files: + - commitizen/__version__.py + - pyproject.toml + customize: + message_template: "{{change_type}}:{% if show_message %} {{message}}{% endif %}" + example: 'feature: this feature enable customize through config file' + schema: "<type>: <body>" + schema_pattern: "(feature|bug fix):(\\s.*)" + bump_pattern: "^(break|new|fix|hotfix)" + bump_map: + break: MAJOR + new: MINOR + fix: PATCH + hotfix: PATCH + info: This is a customized cz. + questions: + - type: list + name: change_type + 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. + - type: confirm + name: show_message + message: Do you want to add body message in commit? +""" + + TOML_STR_INFO_PATH = """ [tool.commitizen.customize] message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" @@ -119,6 +156,21 @@ } """ +YAML_STR_INFO_PATH = """ +commitizen: + customize: + message_template: "{{change_type}}:{% if show_message %} {{message}}{% endif %}" + example: 'feature: this feature enable customize through config file' + schema: "<type>: <body>" + bump_pattern: "^(break|new|fix|hotfix)" + bump_map: + break: MAJOR + new: MINOR + fix: PATCH + hotfix: PATCH + info_path: info.txt +""" + TOML_STR_WITHOUT_INFO = """ [tool.commitizen.customize] message_template = "{{change_type}}:{% if show_message %} {{message}}{% endif %}" @@ -147,6 +199,20 @@ } """ +YAML_STR_WITHOUT_PATH = """ +commitizen: + customize: + message_template: "{{change_type}}:{% if show_message %} {{message}}{% endif %}" + example: 'feature: this feature enable customize through config file' + schema: "<type>: <body>" + bump_pattern: "^(break|new|fix|hotfix)" + bump_map: + break: MAJOR + new: MINOR + fix: PATCH + hotfix: PATCH +""" + @pytest.fixture( params=[ @@ -167,6 +233,7 @@ def config(request): params=[ TomlConfig(data=TOML_STR_INFO_PATH, path="not_exist.toml"), JsonConfig(data=JSON_STR_INFO_PATH, path="not_exist.json"), + YAMLConfig(data=YAML_STR_INFO_PATH, path="not_exist.yaml"), ] ) def config_info(request): @@ -177,6 +244,7 @@ def config_info(request): params=[ TomlConfig(data=TOML_STR_WITHOUT_INFO, path="not_exist.toml"), JsonConfig(data=JSON_STR_WITHOUT_PATH, path="not_exist.json"), + YAMLConfig(data=YAML_STR_WITHOUT_PATH, path="not_exist.yaml"), ] ) def config_without_info(request): From c51a521d8117eb7778b9bb64190ef144c600305e Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 10 Dec 2020 07:35:02 +0000 Subject: [PATCH 298/427] =?UTF-8?q?bump:=20version=202.10.0=20=E2=86=92=20?= =?UTF-8?q?2.11.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 10 ++++++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8da4562f75..7f5286fdbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## v2.11.0 (2020-12-10) + +### Feat + +- add yaml as a config option + +### feat + +- **config**: add support for the new class YAMLConfig at the root of the confi internal package + ## v2.10.0 (2020-12-02) ### Feat diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 1c622223ba..7f6646a762 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.10.0" +__version__ = "2.11.0" diff --git a/pyproject.toml b/pyproject.toml index a449b73281..cb3604b866 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.10.0" +version = "2.11.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.10.0" +version = "2.11.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From aa2959dd41629416f34afc0740ed131504c657f0 Mon Sep 17 00:00:00 2001 From: shaq522 <lsw_hehe@qq.com> Date: Thu, 17 Dec 2020 01:42:00 +0800 Subject: [PATCH 299/427] fix(commit): attach user info to backup for permission denied issue When multi users commit in the same machine shared backup will cause permission deny. To resolve this issue, attach user info to the name of backup commit. --- commitizen/commands/commit.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index 09fb2cbbef..4c6f7aa03c 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -28,7 +28,10 @@ def __init__(self, config: BaseConfig, arguments: dict): self.config: BaseConfig = config self.cz = factory.commiter_factory(self.config) self.arguments = arguments - self.temp_file: str = os.path.join(tempfile.gettempdir(), "cz.commit.backup") + self.temp_file: str = os.path.join( + tempfile.gettempdir(), + "cz.commit{user}.backup".format(user=os.environ.get("USER", "")), + ) def read_backup_message(self) -> str: # Check the commit backup file exists From edc06c3f23d0ba69d5edf2fe752db03b5f7678d0 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 16 Dec 2020 18:34:10 +0000 Subject: [PATCH 300/427] =?UTF-8?q?bump:=20version=202.11.0=20=E2=86=92=20?= =?UTF-8?q?2.11.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f5286fdbc..bc81e4cf3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v2.11.1 (2020-12-16) + +### Fix + +- **commit**: attach user info to backup for permission denied issue + ## v2.11.0 (2020-12-10) ### Feat diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 7f6646a762..200c236308 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.11.0" +__version__ = "2.11.1" diff --git a/pyproject.toml b/pyproject.toml index cb3604b866..de30c25821 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.11.0" +version = "2.11.1" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.11.0" +version = "2.11.1" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 425c020fdf00b72a95509cd931678e44d31d03e2 Mon Sep 17 00:00:00 2001 From: Kyle King <KyleKing@users.noreply.github.com> Date: Thu, 24 Dec 2020 14:16:29 -0500 Subject: [PATCH 301/427] docs: add cz_legacy to 3rd party section --- docs/third-party-commitizen.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/third-party-commitizen.md b/docs/third-party-commitizen.md index d109746d2d..7c27e75d80 100644 --- a/docs/third-party-commitizen.md +++ b/docs/third-party-commitizen.md @@ -18,3 +18,15 @@ Just like *conventional commit* format, but with emojis and optionally time spen It can be installed with `pip install commitizen-emoji`. Usage: `cz --name cz_commitizen_emoji commit`. + +### [Conventional Legacy (cz_legacy)][1] + +An extension of the *conventional commit* format to include user-specified +legacy change types in the `CHANGELOG` while preventing the legacy change types +from being used in new commit messages + +`cz_legacy` can be installed with `pip install cz_legacy` + +See the [README][1] for instructions on configuration + + [1]: https://pypi.org/project/cz_legacy From 155f23c776f8638904138cc6d9e9e7b8e634cde4 Mon Sep 17 00:00:00 2001 From: Aleksandr Panchenko <woklex@gmail.com> Date: Thu, 24 Dec 2020 20:06:13 +0300 Subject: [PATCH 302/427] feat(deps): Update and relax tomlkit version requirement --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index de30c25821..a5aafe8e23 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,7 +50,7 @@ decli = "^0.5.2" colorama = "^0.4.1" termcolor = "^1.1" packaging = ">=19,<21" -tomlkit = "^0.5.3" +tomlkit = ">=0.5.3,<1.0.0" jinja2 = "^2.10.3" pyyaml = ">=3.08" argcomplete = "^1.12.1" From cfd4b1d0a76a0d3325e24e89ceb473f1d6411226 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 30 Dec 2020 02:52:50 +0000 Subject: [PATCH 303/427] =?UTF-8?q?bump:=20version=202.11.1=20=E2=86=92=20?= =?UTF-8?q?2.12.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc81e4cf3e..e6b1bc22a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v2.12.0 (2020-12-30) + +### Feat + +- **deps**: Update and relax tomlkit version requirement + ## v2.11.1 (2020-12-16) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 200c236308..95a6d3a792 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.11.1" +__version__ = "2.12.0" diff --git a/pyproject.toml b/pyproject.toml index a5aafe8e23..d7ae12819b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.11.1" +version = "2.12.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.11.1" +version = "2.12.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From b4352895d1490eb82c7a2ec79e251d828373fc11 Mon Sep 17 00:00:00 2001 From: williamfzc <178894043@qq.com> Date: Wed, 30 Dec 2020 14:54:12 +0800 Subject: [PATCH 304/427] fix: read commit_msg_file with utf-8 --- commitizen/commands/check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commitizen/commands/check.py b/commitizen/commands/check.py index f326b44fa5..33fd08a7d0 100644 --- a/commitizen/commands/check.py +++ b/commitizen/commands/check.py @@ -80,7 +80,7 @@ def __call__(self): def _get_commits(self): # Get commit message from file (--commit-msg-file) if self.commit_msg_file: - with open(self.commit_msg_file, "r") as commit_file: + with open(self.commit_msg_file, "r", encoding="utf-8") as commit_file: commit_title = commit_file.readline() commit_body = commit_file.read() return [git.GitCommit(rev="", title=commit_title, body=commit_body)] From 2b7732d79bcf8658b170782fe9f4bc7614d23c00 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 30 Dec 2020 11:05:10 +0000 Subject: [PATCH 305/427] =?UTF-8?q?bump:=20version=202.12.0=20=E2=86=92=20?= =?UTF-8?q?2.12.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6b1bc22a5..f69d35d4cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v2.12.1 (2020-12-30) + +### Fix + +- read commit_msg_file with utf-8 + ## v2.12.0 (2020-12-30) ### Feat diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 95a6d3a792..96fc614cb2 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.12.0" +__version__ = "2.12.1" diff --git a/pyproject.toml b/pyproject.toml index d7ae12819b..4145ffdabb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.12.0" +version = "2.12.1" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.12.0" +version = "2.12.1" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 1474d393ef4edd47f87742cb6128266cf047998b Mon Sep 17 00:00:00 2001 From: Kyle King <KyleKing@users.noreply.github.com> Date: Sat, 26 Dec 2020 11:50:26 -0500 Subject: [PATCH 306/427] refactor: move expected COMMITS_TREE to global --- tests/test_changelog.py | 537 ++++++++++++++++++++-------------------- 1 file changed, 268 insertions(+), 269 deletions(-) diff --git a/tests/test_changelog.py b/tests/test_changelog.py index b1dc1dc0e7..2721c34795 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -509,293 +509,292 @@ def test_get_commit_tag_is_None(gitcommits, tags): assert current_key is None -def test_generate_tree_from_commits(gitcommits, tags): - parser = defaults.commit_parser - changelog_pattern = defaults.bump_pattern - tree = changelog.generate_tree_from_commits( - gitcommits, tags, parser, changelog_pattern - ) - - assert tuple(tree) == ( - { - "version": "v1.2.0", - "date": "2019-04-19", - "changes": { - "feat": [ - { - "scope": None, - "breaking": None, - "message": "custom cz plugins now support bumping version", - } - ] - }, +COMMITS_TREE = ( + { + "version": "v1.2.0", + "date": "2019-04-19", + "changes": { + "feat": [ + { + "scope": None, + "breaking": None, + "message": "custom cz plugins now support bumping version", + } + ] }, - { - "version": "v1.1.1", - "date": "2019-04-18", - "changes": { - "refactor": [ - { - "scope": None, - "breaking": None, - "message": "changed stdout statements", - }, - { - "scope": "schema", - "breaking": None, - "message": "command logic removed from commitizen base", - }, - { - "scope": "info", - "breaking": None, - "message": "command logic removed from commitizen base", - }, - { - "scope": "example", - "breaking": None, - "message": "command logic removed from commitizen base", - }, - { - "scope": "commit", - "breaking": None, - "message": "moved most of the commit logic to the commit command", - }, - ], - "fix": [ - { - "scope": "bump", - "breaking": None, - "message": "commit message now fits better with semver", - }, - { - "scope": None, - "breaking": None, - "message": "conventional commit 'breaking change' in body instead of title", - }, - ], - }, + }, + { + "version": "v1.1.1", + "date": "2019-04-18", + "changes": { + "refactor": [ + { + "scope": None, + "breaking": None, + "message": "changed stdout statements", + }, + { + "scope": "schema", + "breaking": None, + "message": "command logic removed from commitizen base", + }, + { + "scope": "info", + "breaking": None, + "message": "command logic removed from commitizen base", + }, + { + "scope": "example", + "breaking": None, + "message": "command logic removed from commitizen base", + }, + { + "scope": "commit", + "breaking": None, + "message": "moved most of the commit logic to the commit command", + }, + ], + "fix": [ + { + "scope": "bump", + "breaking": None, + "message": "commit message now fits better with semver", + }, + { + "scope": None, + "breaking": None, + "message": "conventional commit 'breaking change' in body instead of title", + }, + ], }, - { - "version": "v1.1.0", - "date": "2019-04-14", - "changes": { - "feat": [ - { - "scope": None, - "breaking": None, - "message": "new working bump command", - }, - {"scope": None, "breaking": None, "message": "create version tag"}, - { - "scope": None, - "breaking": None, - "message": "update given files with new version", - }, - { - "scope": "config", - "breaking": None, - "message": "new set key, used to set version to cfg", - }, - { - "scope": None, - "breaking": None, - "message": "support for pyproject.toml", - }, - { - "scope": None, - "breaking": None, - "message": "first semantic version bump implementation", - }, - ], - "fix": [ - { - "scope": None, - "breaking": None, - "message": "removed all from commit", - }, - { - "scope": None, - "breaking": None, - "message": "fix config file not working", - }, - ], - "refactor": [ - { - "scope": None, - "breaking": None, - "message": "added commands folder, better integration with decli", - } - ], - }, + }, + { + "version": "v1.1.0", + "date": "2019-04-14", + "changes": { + "feat": [ + { + "scope": None, + "breaking": None, + "message": "new working bump command", + }, + {"scope": None, "breaking": None, "message": "create version tag"}, + { + "scope": None, + "breaking": None, + "message": "update given files with new version", + }, + { + "scope": "config", + "breaking": None, + "message": "new set key, used to set version to cfg", + }, + { + "scope": None, + "breaking": None, + "message": "support for pyproject.toml", + }, + { + "scope": None, + "breaking": None, + "message": "first semantic version bump implementation", + }, + ], + "fix": [ + { + "scope": None, + "breaking": None, + "message": "removed all from commit", + }, + { + "scope": None, + "breaking": None, + "message": "fix config file not working", + }, + ], + "refactor": [ + { + "scope": None, + "breaking": None, + "message": "added commands folder, better integration with decli", + } + ], }, - { - "version": "v1.0.0", - "date": "2019-03-01", - "changes": { - "refactor": [ - { - "scope": None, - "breaking": None, - "message": "removed delegator, added decli and many tests", - } - ], - "BREAKING CHANGE": [ - {"scope": None, "breaking": None, "message": "API is stable"} - ], - }, + }, + { + "version": "v1.0.0", + "date": "2019-03-01", + "changes": { + "refactor": [ + { + "scope": None, + "breaking": None, + "message": "removed delegator, added decli and many tests", + } + ], + "BREAKING CHANGE": [ + {"scope": None, "breaking": None, "message": "API is stable"} + ], }, - {"version": "1.0.0b2", "date": "2019-01-18", "changes": {}}, - { - "version": "v1.0.0b1", - "date": "2019-01-17", - "changes": { - "feat": [ - { - "scope": None, - "breaking": None, - "message": "py3 only, tests and conventional commits 1.0", - } - ] - }, + }, + {"version": "1.0.0b2", "date": "2019-01-18", "changes": {}}, + { + "version": "v1.0.0b1", + "date": "2019-01-17", + "changes": { + "feat": [ + { + "scope": None, + "breaking": None, + "message": "py3 only, tests and conventional commits 1.0", + } + ] }, - { - "version": "v0.9.11", - "date": "2018-12-17", - "changes": { - "fix": [ - { - "scope": "config", - "breaking": None, - "message": "load config reads in order without failing if there is no commitizen section", - } - ] - }, + }, + { + "version": "v0.9.11", + "date": "2018-12-17", + "changes": { + "fix": [ + { + "scope": "config", + "breaking": None, + "message": "load config reads in order without failing if there is no commitizen section", + } + ] }, - { - "version": "v0.9.10", - "date": "2018-09-22", - "changes": { - "fix": [ - { - "scope": None, - "breaking": None, - "message": "parse scope (this is my punishment for not having tests)", - } - ] - }, + }, + { + "version": "v0.9.10", + "date": "2018-09-22", + "changes": { + "fix": [ + { + "scope": None, + "breaking": None, + "message": "parse scope (this is my punishment for not having tests)", + } + ] }, - { - "version": "v0.9.9", - "date": "2018-09-22", - "changes": { - "fix": [ - {"scope": None, "breaking": None, "message": "parse scope empty"} - ] - }, + }, + { + "version": "v0.9.9", + "date": "2018-09-22", + "changes": { + "fix": [{"scope": None, "breaking": None, "message": "parse scope empty"}] }, - { - "version": "v0.9.8", - "date": "2018-09-22", - "changes": { - "fix": [ - { - "scope": "scope", - "breaking": None, - "message": "parse correctly again", - } - ] - }, + }, + { + "version": "v0.9.8", + "date": "2018-09-22", + "changes": { + "fix": [ + { + "scope": "scope", + "breaking": None, + "message": "parse correctly again", + } + ] }, - { - "version": "v0.9.7", - "date": "2018-09-22", - "changes": { - "fix": [ - {"scope": "scope", "breaking": None, "message": "parse correctly"} - ] - }, + }, + { + "version": "v0.9.7", + "date": "2018-09-22", + "changes": { + "fix": [{"scope": "scope", "breaking": None, "message": "parse correctly"}] }, - { - "version": "v0.9.6", - "date": "2018-09-19", - "changes": { - "refactor": [ - { - "scope": "conventionalCommit", - "breaking": None, - "message": "moved filters to questions instead of message", - } - ], - "fix": [ - { - "scope": "manifest", - "breaking": None, - "message": "included missing files", - } - ], - }, + }, + { + "version": "v0.9.6", + "date": "2018-09-19", + "changes": { + "refactor": [ + { + "scope": "conventionalCommit", + "breaking": None, + "message": "moved filters to questions instead of message", + } + ], + "fix": [ + { + "scope": "manifest", + "breaking": None, + "message": "included missing files", + } + ], }, - { - "version": "v0.9.5", - "date": "2018-08-24", - "changes": { - "fix": [ - { - "scope": "config", - "breaking": None, - "message": "home path for python versions between 3.0 and 3.5", - } - ] - }, + }, + { + "version": "v0.9.5", + "date": "2018-08-24", + "changes": { + "fix": [ + { + "scope": "config", + "breaking": None, + "message": "home path for python versions between 3.0 and 3.5", + } + ] }, - { - "version": "v0.9.4", - "date": "2018-08-02", - "changes": { - "feat": [{"scope": "cli", "breaking": None, "message": "added version"}] - }, + }, + { + "version": "v0.9.4", + "date": "2018-08-02", + "changes": { + "feat": [{"scope": "cli", "breaking": None, "message": "added version"}] }, - { - "version": "v0.9.3", - "date": "2018-07-28", - "changes": { - "feat": [ - { - "scope": "committer", - "breaking": None, - "message": "conventional commit is a bit more intelligent now", - } - ] - }, + }, + { + "version": "v0.9.3", + "date": "2018-07-28", + "changes": { + "feat": [ + { + "scope": "committer", + "breaking": None, + "message": "conventional commit is a bit more intelligent now", + } + ] }, - { - "version": "v0.9.2", - "date": "2017-11-11", - "changes": { - "refactor": [ - { - "scope": None, - "breaking": None, - "message": "renamed conventional_changelog to conventional_commits, not backward compatible", - } - ] - }, + }, + { + "version": "v0.9.2", + "date": "2017-11-11", + "changes": { + "refactor": [ + { + "scope": None, + "breaking": None, + "message": "renamed conventional_changelog to conventional_commits, not backward compatible", + } + ] }, - { - "version": "v0.9.1", - "date": "2017-11-11", - "changes": { - "fix": [ - { - "scope": "setup.py", - "breaking": None, - "message": "future is now required for every python version", - } - ] - }, + }, + { + "version": "v0.9.1", + "date": "2017-11-11", + "changes": { + "fix": [ + { + "scope": "setup.py", + "breaking": None, + "message": "future is now required for every python version", + } + ] }, + }, +) + + +def test_generate_tree_from_commits(gitcommits, tags): + parser = defaults.commit_parser + changelog_pattern = defaults.bump_pattern + tree = changelog.generate_tree_from_commits( + gitcommits, tags, parser, changelog_pattern ) + assert tuple(tree) == COMMITS_TREE + def test_render_changelog(gitcommits, tags, changelog_content): parser = defaults.commit_parser From fb083008f5c814586aec20bf52caf1d239a76ab9 Mon Sep 17 00:00:00 2001 From: Kyle King <KyleKing@users.noreply.github.com> Date: Sat, 26 Dec 2020 11:50:47 -0500 Subject: [PATCH 307/427] feat(#319): add optional change_type_order --- commitizen/changelog.py | 18 ++++++++++++++-- commitizen/commands/changelog.py | 5 +++++ commitizen/cz/base.py | 1 + commitizen/cz/customize/customize.py | 5 +++++ commitizen/defaults.py | 2 ++ docs/customization.md | 10 ++++++--- pyproject.toml | 4 ++++ tests/commands/test_changelog_command.py | 1 + tests/test_changelog.py | 27 ++++++++++++++++++++++++ tests/test_cz_customize.py | 14 ++++++++++++ 10 files changed, 82 insertions(+), 5 deletions(-) diff --git a/commitizen/changelog.py b/commitizen/changelog.py index 9084561c15..607c27ede3 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -24,9 +24,10 @@ - [x] hook after changelog is generated (api calls) - [x] add support for change_type maps """ + import os import re -from collections import defaultdict +from collections import OrderedDict, defaultdict from datetime import date from typing import Callable, Dict, Iterable, List, Optional @@ -98,7 +99,7 @@ def generate_tree_from_commits( "date": current_tag_date, "changes": changes, } - # TODO: Check if tag matches the version pattern, otherwie skip it. + # TODO: Check if tag matches the version pattern, otherwise skip it. # This in order to prevent tags that are not versions. current_tag_name = commit_tag.name current_tag_date = commit_tag.date @@ -128,6 +129,19 @@ def generate_tree_from_commits( yield {"version": current_tag_name, "date": current_tag_date, "changes": changes} +def order_changelog_tree(tree: Iterable, change_type_order: List[str]) -> Iterable: + sorted_tree = [] + for entry in tree: + entry_change_types = sorted(entry["changes"].keys()) + ordered_change_types = [] + for ct in change_type_order + entry_change_types: + if ct in entry_change_types and ct not in ordered_change_types: + ordered_change_types.append(ct) + changes = [(ct, entry["changes"][ct]) for ct in ordered_change_types] + sorted_tree.append({**entry, **{"changes": OrderedDict(changes)}}) + return sorted_tree + + def render_changelog(tree: Iterable) -> str: loader = PackageLoader("commitizen", "templates") env = Environment(loader=loader, trim_blocks=True) diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index 62d175d27d..535632dfc0 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -43,6 +43,9 @@ def __init__(self, config: BaseConfig, args): self.change_type_map = ( self.config.settings.get("change_type_map") or self.cz.change_type_map ) + self.change_type_order = ( + self.config.settings.get("change_type_order") or self.cz.change_type_order + ) def _find_incremental_rev(self, latest_version: str, tags: List[GitTag]) -> str: """Try to find the 'start_rev'. @@ -109,6 +112,8 @@ def __call__(self): change_type_map=change_type_map, changelog_message_builder_hook=changelog_message_builder_hook, ) + if self.change_type_order: + tree = changelog.order_changelog_tree(tree, self.change_type_order) changelog_out = changelog.render_changelog(tree) changelog_out = changelog_out.lstrip("\n") diff --git a/commitizen/cz/base.py b/commitizen/cz/base.py index 5871879992..734852c868 100644 --- a/commitizen/cz/base.py +++ b/commitizen/cz/base.py @@ -29,6 +29,7 @@ class BaseCommitizen(metaclass=ABCMeta): commit_parser: Optional[str] = r"(?P<message>.*)" changelog_pattern: Optional[str] = r".*" change_type_map: Optional[Dict[str, str]] = None + change_type_order: Optional[List[str]] = None # Executed per message parsed by the commitizen changelog_message_builder_hook: Optional[ diff --git a/commitizen/cz/customize/customize.py b/commitizen/cz/customize/customize.py index 1c0bb98baf..acf205d06e 100644 --- a/commitizen/cz/customize/customize.py +++ b/commitizen/cz/customize/customize.py @@ -16,6 +16,7 @@ class CustomizeCommitsCz(BaseCommitizen): bump_pattern = defaults.bump_pattern bump_map = defaults.bump_map + change_type_order = defaults.change_type_order def __init__(self, config: BaseConfig): super(CustomizeCommitsCz, self).__init__(config) @@ -32,6 +33,10 @@ def __init__(self, config: BaseConfig): if custom_bump_map: self.bump_map = custom_bump_map + custom_change_type_order = self.custom_settings.get("change_type_order") + if custom_change_type_order: + self.change_type_order = custom_change_type_order + def questions(self) -> List[Dict[str, Any]]: return self.custom_settings.get("questions") diff --git a/commitizen/defaults.py b/commitizen/defaults.py index c5f07992f6..77fc4b0a50 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -40,5 +40,7 @@ ) bump_message = "bump: version $current_version → $new_version" +change_type_order = ["BREAKING CHANGE", "feat", "fix", "refactor", "perf"] + commit_parser = r"^(?P<change_type>feat|fix|refactor|perf|BREAKING CHANGE)(?:\((?P<scope>[^()\r\n]*)\)|\()?(?P<breaking>!)?:\s(?P<message>.*)?" # noqa version_parser = r"(?P<version>([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+)?)" diff --git a/docs/customization.md b/docs/customization.md index 0d86dc057f..bd15498051 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -23,6 +23,7 @@ schema = "<type>: <body>" schema_pattern = "(feature|bug fix):(\\s.*)" bump_pattern = "^(break|new|fix|hotfix)" bump_map = {"break" = "MAJOR", "new" = "MINOR", "fix" = "PATCH", "hotfix" = "PATCH"} +change_type_order = ["BREAKING CHANGE", "feat", "fix", "refactor", "perf"] info_path = "cz_customize_info.txt" info = """ This is customized info @@ -51,7 +52,7 @@ The equivalent example for a json config file: ```json { "commitizen": { - "name": "cz_customize", + "name": "cz_customize", "customize": { "message_template": "{{change_type}}:{% if show_message %} {{message}}{% endif %}", "example": "feature: this feature enable customize through config file", @@ -64,7 +65,8 @@ The equivalent example for a json config file: "fix": "PATCH", "hotfix": "PATCH" }, - "info_path": "cz_customize_info.txt", + "change_type_order": ["BREAKING CHANGE", "feat", "fix", "refactor", "perf"], + "info_path": "cz_customize_info.txt", "info": "This is customized info", "questions": [ { @@ -114,6 +116,7 @@ commitizen: new: MINOR fix: PATCH hotfix: PATCH + change_type_order: ["BREAKING CHANGE", "feat", "fix", "refactor", "perf"] info_path: cz_customize_info.txt info: This is customized info questions: @@ -146,6 +149,7 @@ commitizen: | `info` | `str` | `None` | (OPTIONAL) Explanation of the commit rules. Used by `cz info`. | | `bump_map` | `dict` | `None` | (OPTIONAL) Dictionary mapping the extracted information to a `SemVer` increment type (`MAJOR`, `MINOR`, `PATCH`) | | `bump_pattern` | `str` | `None` | (OPTIONAL) Regex to extract information from commit (subject and body) | +| `change_type_order`| `str` | `None` | (OPTIONAL) List of strings used to order the Changelog. All other types will be sorted alphabetically. Default is `["BREAKING CHANGE", "feat", "fix", "refactor", "perf"]` | #### Detailed `questions` content @@ -298,7 +302,7 @@ You can customize it of course, and this are the variables you need to add to yo | Parameter | Type | Required | Description | | -------------------------------- | ------------------------------------------------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `commit_parser` | `str` | NO | Regex which should provide the variables explained in the [changelog description][changelog-des] | -| `changelog_pattern` | `str` | NO | Regex to validate the commits, this is useful to skip commits that don't meet your rulling standards like a Merge. Usually the same as bump_pattern | +| `changelog_pattern` | `str` | NO | Regex to validate the commits, this is useful to skip commits that don't meet your ruling standards like a Merge. Usually the same as bump_pattern | | `change_type_map` | `dict` | NO | Convert the title of the change type that will appear in the changelog, if a value is not found, the original will be provided | | `changelog_message_builder_hook` | `method: (dict, git.GitCommit) -> dict` | NO | Customize with extra information your message output, like adding links, this function is executed per parsed commit. Each GitCommit contains the following attrs: `rev`, `title`, `body`, `author`, `author_email` | | `changelog_hook` | `method: (full_changelog: str, partial_changelog: Optional[str]) -> str` | NO | Receives the whole and partial (if used incremental) changelog. Useful to send slack messages or notify a compliance department. Must return the full_changelog | diff --git a/pyproject.toml b/pyproject.toml index 4145ffdabb..223abe0606 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,6 +71,9 @@ freezegun = "^0.3.15" pydocstyle = "^5.0.2" pre-commit = "^2.6.0" +# FIXME: Remove for submission (testing issues/319-only) +pytest-watch = "*" + [tool.poetry.scripts] cz = "commitizen.cli:main" git-cz = "commitizen.cli:main" @@ -81,6 +84,7 @@ include_trailing_comma = true force_grid_wrap = 0 combine_as_imports = true line_length = 88 +known_first_party = ["commitizen", "tests"] [tool.coverage] [tool.coverage.report] diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index aceaaf9d96..e5993dbdfa 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -249,6 +249,7 @@ def test_changelog_hook(mocker, config): create_file_and_commit("refactor: is in changelog") create_file_and_commit("Merge into master") + config.settings["change_type_order"] = ["Refactor", "Feat"] changelog = Changelog( config, {"unreleased_version": None, "incremental": True, "dry_run": False} ) diff --git a/tests/test_changelog.py b/tests/test_changelog.py index 2721c34795..440f407ac2 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -796,6 +796,33 @@ def test_generate_tree_from_commits(gitcommits, tags): assert tuple(tree) == COMMITS_TREE +@pytest.mark.parametrize( + "change_type_order, expected_reordering", + ( + ([], {}), + ( + ["BREAKING CHANGE", "refactor"], + { + 2: (["refactor", "feat", "fix"], ["feat", "fix", "refactor"]), + 3: (["BREAKING CHANGE", "refactor"], ["refactor", "BREAKING CHANGE"]), + }, + ), + ), +) +def test_order_changelog_tree(change_type_order, expected_reordering): + tree = tuple(changelog.order_changelog_tree(COMMITS_TREE, change_type_order)) + + index_of_reordered_entry = [*expected_reordering.keys()] + for index, entry in enumerate(tuple(tree)): + if index in index_of_reordered_entry: + sorted_order, original_order = expected_reordering[index] + assert [*tree[index].keys()] == [*COMMITS_TREE[index].keys()] + assert [*tree[index]["changes"].keys()] == sorted_order + assert [*COMMITS_TREE[index]["changes"].keys()] == original_order + else: + assert [*entry["changes"].keys()] == [*tree[index]["changes"].keys()] + + def test_render_changelog(gitcommits, tags, changelog_content): parser = defaults.commit_parser changelog_pattern = defaults.bump_pattern diff --git a/tests/test_cz_customize.py b/tests/test_cz_customize.py index 479fcef7c4..e919093e04 100644 --- a/tests/test_cz_customize.py +++ b/tests/test_cz_customize.py @@ -13,6 +13,7 @@ bump_pattern = "^(break|new|fix|hotfix)" bump_map = {"break" = "MAJOR", "new" = "MINOR", "fix" = "PATCH", "hotfix" = "PATCH"} + change_type_order = ["perf", "BREAKING CHANGE", "feat", "fix", "refactor"] info = "This is a customized cz." [[tool.commitizen.customize.questions]] @@ -56,6 +57,7 @@ "fix": "PATCH", "hotfix": "PATCH" }, + "change_type_order": ["perf", "BREAKING CHANGE", "feat", "fix", "refactor"], "info": "This is a customized cz.", "questions": [ { @@ -107,6 +109,7 @@ new: MINOR fix: PATCH hotfix: PATCH + change_type_order: ["perf", "BREAKING CHANGE", "feat", "fix", "refactor"] info: This is a customized cz. questions: - type: list @@ -274,6 +277,17 @@ def test_bump_map(config): } +def test_change_type_order(config): + cz = CustomizeCommitsCz(config) + assert cz.change_type_order == [ + "perf", + "BREAKING CHANGE", + "feat", + "fix", + "refactor", + ] + + def test_questions(config): cz = CustomizeCommitsCz(config) questions = cz.questions() From bf857f410d51ef8fa1798d304d8670e51db97cb3 Mon Sep 17 00:00:00 2001 From: Kyle King <KyleKing@users.noreply.github.com> Date: Wed, 30 Dec 2020 06:43:20 -0500 Subject: [PATCH 308/427] refactor(#323): address PR feedback --- commitizen/changelog.py | 19 +++++++++++++------ docs/customization.md | 4 ++-- pyproject.toml | 3 --- tests/test_changelog.py | 32 ++++++++++++++++++++++++-------- 4 files changed, 39 insertions(+), 19 deletions(-) diff --git a/commitizen/changelog.py b/commitizen/changelog.py index 607c27ede3..fc2680544d 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -130,14 +130,21 @@ def generate_tree_from_commits( def order_changelog_tree(tree: Iterable, change_type_order: List[str]) -> Iterable: + if len(set(change_type_order)) != len(change_type_order): + raise RuntimeError( + f"Change types contain duplicates types ({change_type_order})" + ) + sorted_tree = [] for entry in tree: - entry_change_types = sorted(entry["changes"].keys()) - ordered_change_types = [] - for ct in change_type_order + entry_change_types: - if ct in entry_change_types and ct not in ordered_change_types: - ordered_change_types.append(ct) - changes = [(ct, entry["changes"][ct]) for ct in ordered_change_types] + ordered_change_types = change_type_order + sorted( + set(entry["changes"].keys()) - set(change_type_order) + ) + changes = [ + (ct, entry["changes"][ct]) + for ct in ordered_change_types + if ct in entry["changes"] + ] sorted_tree.append({**entry, **{"changes": OrderedDict(changes)}}) return sorted_tree diff --git a/docs/customization.md b/docs/customization.md index bd15498051..5e7caaaaaf 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -52,7 +52,7 @@ The equivalent example for a json config file: ```json { "commitizen": { - "name": "cz_customize", + "name": "cz_customize", "customize": { "message_template": "{{change_type}}:{% if show_message %} {{message}}{% endif %}", "example": "feature: this feature enable customize through config file", @@ -66,7 +66,7 @@ The equivalent example for a json config file: "hotfix": "PATCH" }, "change_type_order": ["BREAKING CHANGE", "feat", "fix", "refactor", "perf"], - "info_path": "cz_customize_info.txt", + "info_path": "cz_customize_info.txt", "info": "This is customized info", "questions": [ { diff --git a/pyproject.toml b/pyproject.toml index 223abe0606..e27d1dec0d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,9 +71,6 @@ freezegun = "^0.3.15" pydocstyle = "^5.0.2" pre-commit = "^2.6.0" -# FIXME: Remove for submission (testing issues/319-only) -pytest-watch = "*" - [tool.poetry.scripts] cz = "commitizen.cli:main" git-cz = "commitizen.cli:main" diff --git a/tests/test_changelog.py b/tests/test_changelog.py index 440f407ac2..6696a14348 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -803,26 +803,42 @@ def test_generate_tree_from_commits(gitcommits, tags): ( ["BREAKING CHANGE", "refactor"], { - 2: (["refactor", "feat", "fix"], ["feat", "fix", "refactor"]), - 3: (["BREAKING CHANGE", "refactor"], ["refactor", "BREAKING CHANGE"]), + "1.1.0": { + "original": ["feat", "fix", "refactor"], + "sorted": ["refactor", "feat", "fix"], + }, + "1.0.0": { + "original": ["refactor", "BREAKING CHANGE"], + "sorted": ["BREAKING CHANGE", "refactor"], + }, }, ), ), ) def test_order_changelog_tree(change_type_order, expected_reordering): - tree = tuple(changelog.order_changelog_tree(COMMITS_TREE, change_type_order)) + tree = changelog.order_changelog_tree(COMMITS_TREE, change_type_order) - index_of_reordered_entry = [*expected_reordering.keys()] for index, entry in enumerate(tuple(tree)): - if index in index_of_reordered_entry: - sorted_order, original_order = expected_reordering[index] + version = tree[index]["version"] + if version in expected_reordering: + # Verify that all keys are present assert [*tree[index].keys()] == [*COMMITS_TREE[index].keys()] - assert [*tree[index]["changes"].keys()] == sorted_order - assert [*COMMITS_TREE[index]["changes"].keys()] == original_order + # Verify that the reorder only impacted the returned dict and not the original + expected = expected_reordering[version] + assert [*tree[index]["changes"].keys()] == expected["sorted"] + assert [*COMMITS_TREE[index]["changes"].keys()] == expected["original"] else: assert [*entry["changes"].keys()] == [*tree[index]["changes"].keys()] +def test_order_changelog_tree_raises(): + change_type_order = ["BREAKING CHANGE", "feat", "refactor", "feat"] + with pytest.raises(RuntimeError) as excinfo: + changelog.order_changelog_tree(COMMITS_TREE, change_type_order) + + assert " duplicate" in str(excinfo) + + def test_render_changelog(gitcommits, tags, changelog_content): parser = defaults.commit_parser changelog_pattern = defaults.bump_pattern From 9d1a53ee08c5fbff17f00e032a542c3882c447c8 Mon Sep 17 00:00:00 2001 From: Kyle King <KyleKing@users.noreply.github.com> Date: Wed, 30 Dec 2020 06:45:08 -0500 Subject: [PATCH 309/427] style: restore whitespace for info_path in JSON --- docs/customization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/customization.md b/docs/customization.md index 5e7caaaaaf..204395ed4b 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -66,7 +66,7 @@ The equivalent example for a json config file: "hotfix": "PATCH" }, "change_type_order": ["BREAKING CHANGE", "feat", "fix", "refactor", "perf"], - "info_path": "cz_customize_info.txt", + "info_path": "cz_customize_info.txt", "info": "This is customized info", "questions": [ { From 34ba4004c43888bf1a52c9dce09c8473fb9ae5a7 Mon Sep 17 00:00:00 2001 From: Kyle King <KyleKing@users.noreply.github.com> Date: Thu, 31 Dec 2020 08:29:43 -0500 Subject: [PATCH 310/427] refactor: raise an InvalidConfigurationError --- commitizen/changelog.py | 3 ++- commitizen/exceptions.py | 5 +++++ docs/exit_codes.md | 1 + tests/test_changelog.py | 5 +++-- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/commitizen/changelog.py b/commitizen/changelog.py index fc2680544d..ca36015ed9 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -34,6 +34,7 @@ from jinja2 import Environment, PackageLoader from commitizen import defaults +from commitizen.exceptions import InvalidConfigurationError from commitizen.git import GitCommit, GitTag CATEGORIES = [ @@ -131,7 +132,7 @@ def generate_tree_from_commits( def order_changelog_tree(tree: Iterable, change_type_order: List[str]) -> Iterable: if len(set(change_type_order)) != len(change_type_order): - raise RuntimeError( + raise InvalidConfigurationError( f"Change types contain duplicates types ({change_type_order})" ) diff --git a/commitizen/exceptions.py b/commitizen/exceptions.py index 84219f7fd1..8293688715 100644 --- a/commitizen/exceptions.py +++ b/commitizen/exceptions.py @@ -23,6 +23,7 @@ class ExitCode(enum.IntEnum): NO_REVISION = 16 CURRENT_VERSION_NOT_FOUND = 17 INVALID_COMMAND_ARGUMENT = 18 + INVALID_CONFIGURATION = 19 class CommitizenException(Exception): @@ -137,3 +138,7 @@ class NoCommandFoundError(CommitizenException): class InvalidCommandArgumentError(CommitizenException): exit_code = ExitCode.INVALID_COMMAND_ARGUMENT + + +class InvalidConfigurationError(CommitizenException): + exit_code = ExitCode.INVALID_CONFIGURATION diff --git a/docs/exit_codes.md b/docs/exit_codes.md index d83c93d991..cae66b8bab 100644 --- a/docs/exit_codes.md +++ b/docs/exit_codes.md @@ -26,3 +26,4 @@ These exit codes can be found in `commitizen/exceptions.py::ExitCode`. | NoRevisionError | 16 | No revision found | | CurrentVersionNotFoundError | 17 | current version cannot be found in *version_files* | | InvalidCommandArgumentError | 18 | The argument provide to command is invalid (e.g. `cz check -commit-msg-file filename --rev-range master..`) | +| InvalidConfigurationError | 19 | An error was found in the Commitizen Configuration, such as duplicates in `change_type_order` | diff --git a/tests/test_changelog.py b/tests/test_changelog.py index 6696a14348..055e4fc916 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -1,6 +1,7 @@ import pytest from commitizen import changelog, defaults, git +from commitizen.exceptions import InvalidConfigurationError COMMITS_DATA = [ { @@ -833,10 +834,10 @@ def test_order_changelog_tree(change_type_order, expected_reordering): def test_order_changelog_tree_raises(): change_type_order = ["BREAKING CHANGE", "feat", "refactor", "feat"] - with pytest.raises(RuntimeError) as excinfo: + with pytest.raises(InvalidConfigurationError) as excinfo: changelog.order_changelog_tree(COMMITS_TREE, change_type_order) - assert " duplicate" in str(excinfo) + assert "Change types contain duplicates types" in str(excinfo) def test_render_changelog(gitcommits, tags, changelog_content): From 03406b042d763e97a1ee9e21a1bec1d352d2d705 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Fri, 1 Jan 2021 04:00:00 +0000 Subject: [PATCH 311/427] =?UTF-8?q?bump:=20version=202.12.1=20=E2=86=92=20?= =?UTF-8?q?2.13.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 12 ++++++++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f69d35d4cb..d41450f03b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## v2.13.0 (2021-01-01) + +### Refactor + +- raise an InvalidConfigurationError +- **#323**: address PR feedback +- move expected COMMITS_TREE to global + +### Feat + +- **#319**: add optional change_type_order + ## v2.12.1 (2020-12-30) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 96fc614cb2..930e2cd686 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.12.1" +__version__ = "2.13.0" diff --git a/pyproject.toml b/pyproject.toml index e27d1dec0d..fca093493e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.12.1" +version = "2.13.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.12.1" +version = "2.13.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 99d4024e0d80a00d1ff1439b5977d447b6e82e70 Mon Sep 17 00:00:00 2001 From: Kyle King <KyleKing@users.noreply.github.com> Date: Thu, 31 Dec 2020 10:28:13 -0500 Subject: [PATCH 312/427] build(#325): upgrade isort for black compatibility --- pyproject.toml | 8 ++------ scripts/format | 2 +- scripts/test | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index fca093493e..e4b5e6ae88 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,7 +66,7 @@ codecov = "^2.0" mypy = "^0.770" mkdocs = "^1.0" mkdocs-material = "^4.1" -isort = "^4.3.21" +isort = "^5.7.0" freezegun = "^0.3.15" pydocstyle = "^5.0.2" pre-commit = "^2.6.0" @@ -76,11 +76,7 @@ cz = "commitizen.cli:main" git-cz = "commitizen.cli:main" [tool.isort] -multi_line_output = 3 -include_trailing_comma = true -force_grid_wrap = 0 -combine_as_imports = true -line_length = 88 +profile = "black" known_first_party = ["commitizen", "tests"] [tool.coverage] diff --git a/scripts/format b/scripts/format index c643dbc14b..47b2b90f44 100755 --- a/scripts/format +++ b/scripts/format @@ -7,5 +7,5 @@ fi set -x -${PREFIX}isort --recursive --apply commitizen tests +${PREFIX}isort commitizen tests ${PREFIX}black commitizen tests diff --git a/scripts/test b/scripts/test index 6b4f81c81b..08c54035dc 100755 --- a/scripts/test +++ b/scripts/test @@ -7,7 +7,7 @@ fi ${PREFIX}pytest --cov-report term-missing --cov-report=xml:coverage.xml --cov=commitizen tests/ ${PREFIX}black commitizen tests --check -${PREFIX}isort --recursive --check-only commitizen tests +${PREFIX}isort --check-only commitizen tests ${PREFIX}flake8 commitizen/ tests/ ${PREFIX}mypy commitizen/ tests/ ${PREFIX}pydocstyle --convention=google --add-ignore=D1,D415 From 1a33099c2d1450f6c6146f670f492e313e9273c5 Mon Sep 17 00:00:00 2001 From: Serpa <74364272+serpa-dystematic@users.noreply.github.com> Date: Fri, 15 Jan 2021 16:29:15 +0000 Subject: [PATCH 313/427] docs(bump): update cli tag format flag --- docs/bump.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/bump.md b/docs/bump.md index 668120588d..e78b92265c 100644 --- a/docs/bump.md +++ b/docs/bump.md @@ -167,11 +167,11 @@ It is used to read the format from the git tags, and also to generate the tags. Commitizen supports 2 types of formats, a simple and a more complex. ```bash -cz bump --tag_format="v$version" +cz bump --tag-format="v$version" ``` ```bash -cz bump --tag_format="v$minor.$major.$patch$prerelease" +cz bump --tag-format="v$minor.$major.$patch$prerelease" ``` In your `pyproject.toml` or `.cz.toml` From 20a54bf1b82cd7b573351db4d1e8814dd0be205d Mon Sep 17 00:00:00 2001 From: Oliver Berger <oliver@digitalarchitekt.de> Date: Tue, 22 Sep 2020 15:14:09 +0200 Subject: [PATCH 314/427] feat(#271): enable creation of annotated tags when bumping --- commitizen/cli.py | 5 +++++ commitizen/commands/bump.py | 14 +++++++++++-- commitizen/git.py | 4 ++-- docs/bump.md | 32 +++++++++++++++++++++-------- tests/commands/test_bump_command.py | 32 ++++++++++++++++++++++++++++- 5 files changed, 73 insertions(+), 14 deletions(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index 45aa33f303..0436155d05 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -137,6 +137,11 @@ ), "action": "store_true", }, + { + "name": ["--annotated-tag", "-at"], + "help": "create annotated tag instead of lightweight one", + "action": "store_true", + }, ], }, { diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 666e29535d..16c12de0ec 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -32,7 +32,13 @@ def __init__(self, config: BaseConfig, arguments: dict): **config.settings, **{ key: arguments[key] - for key in ["tag_format", "prerelease", "increment", "bump_message"] + for key in [ + "tag_format", + "prerelease", + "increment", + "bump_message", + "annotated_tag", + ] if arguments[key] is not None }, } @@ -183,7 +189,11 @@ def __call__(self): # noqa: C901 c = git.commit(message, args=self._get_commit_args()) if c.return_code != 0: raise BumpCommitFailedError(f'git.commit error: "{c.err.strip()}"') - c = git.tag(new_tag_version) + c = git.tag( + new_tag_version, + annotated=self.bump_settings.get("annotated_tag", False) + or bool(self.config.settings.get("annotated_tag", False)), + ) if c.return_code != 0: raise BumpTagFailedError(c.err) out.success("Done!") diff --git a/commitizen/git.py b/commitizen/git.py index 06ad240367..caaadd822f 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -45,8 +45,8 @@ def __repr__(self): return f"GitTag('{self.name}', '{self.rev}', '{self.date}')" -def tag(tag: str): - c = cmd.run(f"git tag {tag}") +def tag(tag: str, annotated: bool = False): + c = cmd.run(f"git tag -a {tag} -m {tag}" if annotated else f"git tag {tag}") return c diff --git a/docs/bump.md b/docs/bump.md index 668120588d..3c92b965ee 100644 --- a/docs/bump.md +++ b/docs/bump.md @@ -57,30 +57,29 @@ $ cz bump --help usage: cz bump [-h] [--dry-run] [--files-only] [--changelog] [--no-verify] [--local-version] [--yes] [--tag-format TAG_FORMAT] [--bump-message BUMP_MESSAGE] [--prerelease {alpha,beta,rc}] - [--increment {MAJOR,MINOR,PATCH}] [--check-consistency] + [--increment {MAJOR,MINOR,PATCH}] [--check-consistency] [--annotated-tag] 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 --changelog, -ch generate the changelog for the newest version - --no-verify this option bypasses the pre-commit and commit-msg - hooks + --no-verify this option bypasses the pre-commit and commit-msg hooks --yes accept automatically questions done --local-version bump the local portion of the version --tag-format TAG_FORMAT - the format used to tag the commit and read it, use it - in existing projects, wrap around simple quotes + the format used to tag the commit and read it, use it in existing projects, wrap + around simple quotes --bump-message BUMP_MESSAGE - template used to create the release commit, useful - when working with CI + template used to create the release commit, useful when working with CI --prerelease {alpha,beta,rc}, -pr {alpha,beta,rc} choose type of prerelease --increment {MAJOR,MINOR,PATCH} manually specify the desired increment --check-consistency, -cc - check consistency among versions defined in commitizen - configuration and version_files + check consistency among versions defined in commitizen configuration and + version_files + --annotated-tag, -at create annotated tag instead of lightweight one ``` ### `--files-only` @@ -158,6 +157,10 @@ version = "5.3.5+0.1.0" If `--local-version` is used, it will bump only the local version `0.1.0` and keep the public version `5.3.5` intact, bumping to the version `5.3.5+0.2.0`. +### `--annotated-tag` + +If `--annotated-tag` is used, commitizen will create annotated tags. Also available via configuration, in `pyproject.toml` or `.cz.toml`. + ## Configuration ### `tag_format` @@ -256,6 +259,17 @@ defaults to: `false` update_changelog_on_bump = true ``` +--- + +### `annotated_tag` + +When set to `true` commitizen will create annotated tags. + +```toml +[tool.commitizen] +annotated_tag = true +``` + ## Custom bump Read the [customizing section](./customization.md). diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index 77ea4840b0..ff4acd7a04 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -49,7 +49,37 @@ def test_bump_minor_increment(commit_msg, mocker): mocker.patch.object(sys, "argv", testargs) cli.main() tag_exists = git.tag_exist("0.2.0") - assert tag_exists is True + cmd_res = cmd.run('git for-each-ref refs/tags --format "%(objecttype):%(refname)"') + assert tag_exists is True and "commit:refs/tags/0.2.0\n" in cmd_res.out + + +@pytest.mark.parametrize("commit_msg", ("feat: new file", "feat(user): new file")) +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_bump_minor_increment_annotated(commit_msg, mocker): + create_file_and_commit(commit_msg) + testargs = ["cz", "bump", "--yes", "--annotated-tag"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + tag_exists = git.tag_exist("0.2.0") + cmd_res = cmd.run('git for-each-ref refs/tags --format "%(objecttype):%(refname)"') + assert tag_exists is True and "tag:refs/tags/0.2.0\n" in cmd_res.out + + +@pytest.mark.parametrize("commit_msg", ("feat: new file", "feat(user): new file")) +def test_bump_minor_increment_annotated_config_file( + commit_msg, mocker, tmp_commitizen_project +): + tmp_commitizen_cfg_file = tmp_commitizen_project.join("pyproject.toml") + tmp_commitizen_cfg_file.write( + f"{tmp_commitizen_cfg_file.read()}\n" f"annotated_tag = 1" + ) + create_file_and_commit(commit_msg) + testargs = ["cz", "bump", "--yes"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + tag_exists = git.tag_exist("0.2.0") + cmd_res = cmd.run('git for-each-ref refs/tags --format "%(objecttype):%(refname)"') + assert tag_exists is True and "tag:refs/tags/0.2.0\n" in cmd_res.out @pytest.mark.usefixtures("tmp_commitizen_project") From ae9ba6fc5526cf478f52ef901418d85505109744 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 20 Jan 2021 16:02:14 +0000 Subject: [PATCH 315/427] =?UTF-8?q?bump:=20version=202.13.0=20=E2=86=92=20?= =?UTF-8?q?2.14.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d41450f03b..baf064bb59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v2.14.0 (2021-01-20) + +### Feat + +- **#271**: enable creation of annotated tags when bumping + ## v2.13.0 (2021-01-01) ### Refactor diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 930e2cd686..d0979fd030 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.13.0" +__version__ = "2.14.0" diff --git a/pyproject.toml b/pyproject.toml index e4b5e6ae88..656f81fc5d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.13.0" +version = "2.14.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.13.0" +version = "2.14.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 427a9ec56c8003e1b1e05176cdece4a548fb91e1 Mon Sep 17 00:00:00 2001 From: Vinay Vennela <52368723+vinayvennela@users.noreply.github.com> Date: Tue, 2 Feb 2021 11:14:14 +0530 Subject: [PATCH 316/427] fix: remove yaml warnings when using '.cz.yaml' --- commitizen/config/yaml_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commitizen/config/yaml_config.py b/commitizen/config/yaml_config.py index cc6c5f0338..510882b9b0 100644 --- a/commitizen/config/yaml_config.py +++ b/commitizen/config/yaml_config.py @@ -38,7 +38,7 @@ def set_key(self, key, value): We use to update the version number. """ with open(self.path, "r") as yaml_file: - parser = yaml.load(yaml_file) + parser = yaml.load(yaml_file, Loader=yaml.FullLoader) parser["commitizen"][key] = value with open(self.path, "w") as yaml_file: From aaba2b6992b4677740ce20bc8800fa64e7c8fb6c Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Tue, 2 Feb 2021 09:24:34 +0000 Subject: [PATCH 317/427] =?UTF-8?q?bump:=20version=202.14.0=20=E2=86=92=20?= =?UTF-8?q?2.14.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index baf064bb59..5bc01f3063 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v2.14.1 (2021-02-02) + +### Fix + +- remove yaml warnings when using '.cz.yaml' + ## v2.14.0 (2021-01-20) ### Feat diff --git a/commitizen/__version__.py b/commitizen/__version__.py index d0979fd030..e199aa5550 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.14.0" +__version__ = "2.14.1" diff --git a/pyproject.toml b/pyproject.toml index 656f81fc5d..0dd3076b02 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.14.0" +version = "2.14.1" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.14.0" +version = "2.14.1" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 3ef52577e648466aa39ea9e40e554f0e55dde15e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Tue, 2 Feb 2021 10:34:27 +0100 Subject: [PATCH 318/427] ci: attempt to fix homebrew action --- .github/workflows/homebrewpublish.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/homebrewpublish.yaml b/.github/workflows/homebrewpublish.yaml index fee4a70405..267ba4ec33 100644 --- a/.github/workflows/homebrewpublish.yaml +++ b/.github/workflows/homebrewpublish.yaml @@ -8,7 +8,7 @@ on: jobs: deploy: - runs-on: ubuntu-latest + runs-on: macos-latest if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - name: Checkout From 58c9c5a1024932b9ea7dbce98066d0fc156c074a Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Thu, 4 Feb 2021 18:52:36 +0800 Subject: [PATCH 319/427] fix(git): handle the empty commit and empty email cases --- commitizen/git.py | 3 +-- tests/test_git.py | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/commitizen/git.py b/commitizen/git.py index caaadd822f..e50152296b 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -79,8 +79,7 @@ def get_commits( return [] git_commits = [] - for rev_and_commit in c.out.split(delimiter): - rev_and_commit = rev_and_commit.strip() + for rev_and_commit in c.out.split(f"\n{delimiter}\n"): if not rev_and_commit: continue rev, title, author, author_email, *body_list = rev_and_commit.split("\n") diff --git a/tests/test_git.py b/tests/test_git.py index bcbca58bb0..88c310e3c6 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -73,6 +73,33 @@ def test_get_commits_author_and_email(): assert "@" in commit.author_email +def test_get_commits_without_email(mocker): + raw_commit = ( + "a515bb8f71c403f6f7d1c17b9d8ebf2ce3959395\n" + "\n" + "user name\n" + "\n" + "----------commit-delimiter----------\n" + "12d3b4bdaa996ea7067a07660bb5df4772297bdd\n" + "feat(users): add username\n" + "user name\n" + "\n" + "----------commit-delimiter----------\n" + ) + mocker.patch("commitizen.cmd.run", return_value=FakeCommand(out=raw_commit)) + + commits = git.get_commits() + + assert commits[0].author == "user name" + assert commits[1].author == "user name" + + assert commits[0].author_email == "" + assert commits[1].author_email == "" + + assert commits[0].title == "" + assert commits[1].title == "feat(users): add username" + + def test_get_tag_names_has_correct_arrow_annotation(): arrow_annotation = inspect.getfullargspec(git.get_tag_names).annotations["return"] From d6a817cbbabb56fd4c37e76bc70aed6796b31ef2 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Thu, 4 Feb 2021 18:52:52 +0800 Subject: [PATCH 320/427] style(init): remove unused comment out --- commitizen/commands/init.py | 1 - 1 file changed, 1 deletion(-) diff --git a/commitizen/commands/init.py b/commitizen/commands/init.py index 96b06f2080..eed9b83ae4 100644 --- a/commitizen/commands/init.py +++ b/commitizen/commands/init.py @@ -122,7 +122,6 @@ def _install_pre_commit_hook(self): # .pre-commit-config does not exist config_data["repos"] = [cz_hook_config] else: - # breakpoint() with open(pre_commit_config_filename) as config_file: yaml_data = yaml.safe_load(config_file) if yaml_data: From f01a03c5dc6fb3e364b730743bc33ab41f9986d9 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 6 Feb 2021 10:12:44 +0800 Subject: [PATCH 321/427] test(git): add test case to get_latest_tag_name --- tests/test_git.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/test_git.py b/tests/test_git.py index 88c310e3c6..b66ae60a92 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -3,7 +3,7 @@ import pytest -from commitizen import git +from commitizen import cmd, git from tests.utils import FakeCommand, create_file_and_commit @@ -104,3 +104,14 @@ def test_get_tag_names_has_correct_arrow_annotation(): arrow_annotation = inspect.getfullargspec(git.get_tag_names).annotations["return"] assert arrow_annotation == List[Optional[str]] + + +def test_get_latest_tag_name(tmp_commitizen_project): + with tmp_commitizen_project.as_cwd(): + tag_name = git.get_latest_tag_name() + assert tag_name is None + + create_file_and_commit("feat(test): test") + cmd.run("git tag 1.0") + tag_name = git.get_latest_tag_name() + assert tag_name == "1.0" From 055fc17260676114e83f64acefe4c0ece4fb5677 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 6 Feb 2021 10:27:47 +0800 Subject: [PATCH 322/427] docs(readme): add download count badge --- docs/README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/README.md b/docs/README.md index 52fc9d444e..05bdc79a22 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,10 +1,8 @@ [![Github Actions](https://github.com/commitizen-tools/commitizen/workflows/Python%20package/badge.svg?style=flat-square)](https://github.com/commitizen-tools/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 -release](https://img.shields.io/pypi/v/commitizen.svg?style=flat-square)](https://pypi.org/project/commitizen/) -[![Supported -versions](https://img.shields.io/pypi/pyversions/commitizen.svg?style=flat-square)](https://pypi.org/project/commitizen/) +[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg?style=flat-square)](https://conventionalcommits.org) +[![PyPI Package latest release](https://img.shields.io/pypi/v/commitizen.svg?style=flat-square)](https://pypi.org/project/commitizen/) +[![PyPI Package download count (per month)](https://img.shields.io/pypi/dm/commitizen?style=flat-square)](https://pypi.org/project/commitizen/) +[![Supported versions](https://img.shields.io/pypi/pyversions/commitizen.svg?style=flat-square)](https://pypi.org/project/commitizen/) [![homebrew](https://img.shields.io/homebrew/v/commitizen?color=teal&style=flat-square)](https://formulae.brew.sh/formula/commitizen) [![Codecov](https://img.shields.io/codecov/c/github/commitizen-tools/commitizen.svg?style=flat-square)](https://codecov.io/gh/commitizen-tools/commitizen) From 8fabcff9a3de5a5f76c6fbe9e08745b10dac0c61 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sat, 6 Feb 2021 09:40:49 +0000 Subject: [PATCH 323/427] =?UTF-8?q?bump:=20version=202.14.1=20=E2=86=92=20?= =?UTF-8?q?2.14.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bc01f3063..c5091a188e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v2.14.2 (2021-02-06) + +### Fix + +- **git**: handle the empty commit and empty email cases + ## v2.14.1 (2021-02-02) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index e199aa5550..abe7e03a96 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.14.1" +__version__ = "2.14.2" diff --git a/pyproject.toml b/pyproject.toml index 0dd3076b02..37c99f2110 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.14.1" +version = "2.14.2" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.14.1" +version = "2.14.2" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 3fdf42d96035dea8f52ccd83da17856e9906a532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sun, 7 Feb 2021 18:45:54 +0100 Subject: [PATCH 324/427] docs(faq): add new questions to faq --- docs/faq.md | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/docs/faq.md b/docs/faq.md index ab6bb97fa1..37300c88e1 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -26,3 +26,50 @@ version_files = [ "package.json:\"version\":" ] ``` + +### Why are `revert` and `chore` valid types in the check pattern of cz conventional_commits but not types we can select? + +`revert` and `chore` are added to the "pattern" in `cz check` in order to prevent backward errors, but officially they are not part of conventional commits, we are using the latest [types from Angular](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#type) (they used to but were removed). +However, you can create a customized `cz` with those extra types. (See [Customization](https://commitizen-tools.github.io/commitizen/customization/) + +See more discussion in issue [#142](https://github.com/commitizen-tools/commitizen/issues/142) and [#36](https://github.com/commitizen-tools/commitizen/issues/36) + +### How to revert a bump? + +If for any reason, the created tag and changelog were to be undone, this is the snippet: + +```sh +git tag --delete <created_tag> +git reset HEAD~ +git reset --hard HEAD +``` + +This will remove the last tag created, plus the commit containing the update to `.cz.toml` and the changelog generated for the version. + +In case the commit was pushed to the server you can remove it by running + +```sh +git push --delete origin <created_tag> +``` + +## Is this project affiliated with the Commitizen JS project? + +It is not affiliated. + +Both are used for similar purposes, parsing commits, generating changelog and version we presume. +This one is written in python to make integration easier for python projects and the other serves the JS packages. + +They differ a bit in design, not sure if cz-js does any of this, but these are some of the stuff you can do with this repo (python's commitizen): + +- create custom rules, version bumps and changelog generation, by default we use the popular conventional commits (I think cz-js allows this). +- single package, install one thing and it will work (cz-js is a monorepo, but you have to install different dependencies AFAIK) +- pre-commit integration +- works on any language project, as long as you create the `.cz.toml` file. + +Where do they cross paths? + +If you are using conventional commits in your git history, then you could swap one with the other in theory. + +Regarding the name, [cz-js][cz-js] came first, they used the word commitizen first. When this project was created originally, the creator read "be a good commitizen", and thought it was just a cool word that made sense, and this would be a package that helps you be a good "commit citizen". + +[cz-js]: https://github.com/commitizen/cz-cli From bf3fce4ec4f7123bcb7ff7ad817766e05513cc6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sun, 7 Feb 2021 19:00:36 +0100 Subject: [PATCH 325/427] docs: update links on resources --- docs/external_links.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/external_links.md b/docs/external_links.md index b31ac85bb3..69ad952c66 100644 --- a/docs/external_links.md +++ b/docs/external_links.md @@ -1,14 +1,16 @@ +> If you have written over commitizen, make a PR and add the link here 💪 + ## Talks -- commitizen-tools: What can we gain from crafting a git message convention - - Speaker: Wei Lee - - Occasion: Taipey.py 2020 June Meetup, Remote Python Pizza 2020 - - Material - - [slides](https://speakerdeck.com/leew/commitizen-tools-what-can-we-gain-from-crafting-a-git-message-convention-at-taipey-dot-py) +| Name | Speaker | Occasion | Language | Extra | +| ------------------------------------------------------------------------- | --------------- | ---------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- | +| commitizen-tools: What can we gain from crafting a git message convention | Wei Lee | Taipey.py 2020 June Meetup, Remote Python Pizza 2020 | English | [slides](https://speakerdeck.com/leew/commitizen-tools-what-can-we-gain-from-crafting-a-git-message-convention-at-taipey-dot-py) | +| Automating release cycles | Santiago Fraire | PyAmsterdam June 24, 2020, Online | English | [slides](https://woile.github.io/commitizen-presentation/) | +| [Automatizando Releases con Commitizen y Github Actions][automatizando] | Santiago Fraire | PyConAr 2020, Remote | Español | [slides](https://woile.github.io/automating-releases-github-actions-presentation/#/) | ## Articles - [Python Table Manners - Commitizen: 規格化 commit message](https://lee-w.github.io/posts/tech/2020/03/python-table-manners-commitizen/) (Written in Traditional Mandarin) -- [Automating semantic release with commitizen](http://woile.github.io/posts/automating-semver-releases-with-commitizen/) (English) +- [Automating semantic release with commitizen](https://woile.dev/posts/automating-semver-releases-with-commitizen/) (English) -> If you have written about commitizen, you can make a PR to add the link here 💪 +[automatizando]: https://youtu.be/t3aE2M8UPBo From 1605d699f03f61432120febdc32e096ad4e3ee7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Tue, 9 Feb 2021 09:04:54 +0100 Subject: [PATCH 326/427] docs: correct title in faq --- docs/faq.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/faq.md b/docs/faq.md index 37300c88e1..c0e22cefde 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -27,14 +27,14 @@ version_files = [ ] ``` -### Why are `revert` and `chore` valid types in the check pattern of cz conventional_commits but not types we can select? +## Why are `revert` and `chore` valid types in the check pattern of cz conventional_commits but not types we can select? `revert` and `chore` are added to the "pattern" in `cz check` in order to prevent backward errors, but officially they are not part of conventional commits, we are using the latest [types from Angular](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#type) (they used to but were removed). However, you can create a customized `cz` with those extra types. (See [Customization](https://commitizen-tools.github.io/commitizen/customization/) See more discussion in issue [#142](https://github.com/commitizen-tools/commitizen/issues/142) and [#36](https://github.com/commitizen-tools/commitizen/issues/36) -### How to revert a bump? +## How to revert a bump? If for any reason, the created tag and changelog were to be undone, this is the snippet: From 0621bc475eeb80dc8c035a61226bb093adc6329a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Fri, 19 Feb 2021 12:14:44 +0100 Subject: [PATCH 327/427] feat(changelog): add support for multiline BREAKING paragraph Closes #346 --- commitizen/changelog.py | 15 +++++++++++++-- setup.cfg | 2 +- tests/commands/test_changelog_command.py | 24 ++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/commitizen/changelog.py b/commitizen/changelog.py index ca36015ed9..7bb9007cdc 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -76,6 +76,8 @@ def generate_tree_from_commits( ) -> Iterable[Dict]: pat = re.compile(changelog_pattern) map_pat = re.compile(commit_parser, re.MULTILINE) + body_map_pat = re.compile(commit_parser, re.MULTILINE | re.DOTALL) + # Check if the latest commit is not tagged latest_commit = commits[0] current_tag: Optional[GitTag] = get_commit_tag(latest_commit, tags) @@ -110,8 +112,8 @@ def generate_tree_from_commits( if not matches: continue + # Process subject from commit message message = map_pat.match(commit.message) - message_body = map_pat.search(commit.body) if message: parsed_message: Dict = message.groupdict() # change_type becomes optional by providing None @@ -122,9 +124,18 @@ def generate_tree_from_commits( if changelog_message_builder_hook: parsed_message = changelog_message_builder_hook(parsed_message, commit) changes[change_type].append(parsed_message) - if message_body: + + # Process body from commit message + body_parts = commit.body.split("\n\n") + for body_part in body_parts: + message_body = body_map_pat.match(body_part) + if not message_body: + continue parsed_message_body: Dict = message_body.groupdict() + change_type = parsed_message_body.pop("change_type", None) + if change_type_map: + change_type = change_type_map.get(change_type, change_type) changes[change_type].append(parsed_message_body) yield {"version": current_tag_name, "date": current_tag_date, "changes": changes} diff --git a/setup.cfg b/setup.cfg index de0172c175..d4e21ad5b3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -35,4 +35,4 @@ exclude = build, dist max-line-length = 88 -max-complexity = 11 +max-complexity = 12 diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index e5993dbdfa..7448fee320 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -386,6 +386,30 @@ def test_breaking_change_content_v1(mocker, capsys): ) +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_breaking_change_content_v1_multiline(mocker, capsys): + commit_message = ( + "feat(users): email pattern corrected\n\n" + "body content\n\n" + "BREAKING CHANGE: migrate by renaming user to users.\n" + "and then connect the thingy with the other thingy\n\n" + "footer content" + ) + create_file_and_commit(commit_message) + testargs = ["cz", "changelog", "--dry-run"] + mocker.patch.object(sys, "argv", testargs) + with pytest.raises(DryRunExit): + cli.main() + out, _ = capsys.readouterr() + + assert out == ( + "## Unreleased\n\n### Feat\n\n- **users**: email pattern corrected\n\n" + "### BREAKING CHANGE\n\n- migrate by renaming user to users.\n" + "and then connect the thingy with the other thingy" + "\n\n" + ) + + @pytest.mark.usefixtures("tmp_commitizen_project") def test_changelog_config_flag_increment(mocker, changelog_path, config_path): From 85f0cb906aa3b74476fc0b4c7abf1d2cf90913be Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sun, 21 Feb 2021 10:11:08 +0000 Subject: [PATCH 328/427] =?UTF-8?q?bump:=20version=202.14.2=20=E2=86=92=20?= =?UTF-8?q?2.15.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 ++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5091a188e..863b358077 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## v2.15.0 (2021-02-21) + ## v2.14.2 (2021-02-06) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index abe7e03a96..90c1ae3a02 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.14.2" +__version__ = "2.15.0" diff --git a/pyproject.toml b/pyproject.toml index 37c99f2110..aab052f856 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.14.2" +version = "2.15.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.14.2" +version = "2.15.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 4671258523cf331904080753c9d83c3cf8b55388 Mon Sep 17 00:00:00 2001 From: longhao <longhao@corp.netease.com> Date: Sun, 21 Feb 2021 23:54:15 +0800 Subject: [PATCH 329/427] fix(config): change read mode from `r` to `rb` --- commitizen/config/__init__.py | 4 ++-- commitizen/config/base_config.py | 2 +- commitizen/config/json_config.py | 6 +++--- commitizen/config/toml_config.py | 6 +++--- commitizen/config/yaml_config.py | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/commitizen/config/__init__.py b/commitizen/config/__init__.py index 2cbd544825..e4e414437c 100644 --- a/commitizen/config/__init__.py +++ b/commitizen/config/__init__.py @@ -28,8 +28,8 @@ def read_cfg() -> BaseConfig: _conf: Union[TomlConfig, JsonConfig, YAMLConfig] - with open(filename, "r") as f: - data: str = f.read() + with open(filename, "rb") as f: + data: bytes = f.read() if "toml" in filename.suffix: _conf = TomlConfig(data=data, path=filename) diff --git a/commitizen/config/base_config.py b/commitizen/config/base_config.py index f3e0767dd2..76cd1706e1 100644 --- a/commitizen/config/base_config.py +++ b/commitizen/config/base_config.py @@ -31,5 +31,5 @@ def update(self, data: dict): def add_path(self, path: Union[str, Path]): self._path = Path(path) - def _parse_setting(self, data: str) -> dict: + def _parse_setting(self, data: Union[bytes, str]) -> dict: raise NotImplementedError() diff --git a/commitizen/config/json_config.py b/commitizen/config/json_config.py index fbf37bbd83..725e37a0eb 100644 --- a/commitizen/config/json_config.py +++ b/commitizen/config/json_config.py @@ -6,7 +6,7 @@ class JsonConfig(BaseConfig): - def __init__(self, *, data: str, path: Union[Path, str]): + def __init__(self, *, data: Union[bytes, str], path: Union[Path, str]): super(JsonConfig, self).__init__() self.is_empty_config = False self._parse_setting(data) @@ -22,7 +22,7 @@ def set_key(self, key, value): For now only strings are supported. We use to update the version number. """ - with open(self.path, "r") as f: + with open(self.path, "rb") as f: parser = json.load(f) parser["commitizen"][key] = value @@ -30,7 +30,7 @@ def set_key(self, key, value): json.dump(parser, f) return self - def _parse_setting(self, data: str): + def _parse_setting(self, data: Union[bytes, str]): """We expect to have a section in .cz.json looking like ``` diff --git a/commitizen/config/toml_config.py b/commitizen/config/toml_config.py index a9b3cfab1e..27ab47d4e2 100644 --- a/commitizen/config/toml_config.py +++ b/commitizen/config/toml_config.py @@ -7,7 +7,7 @@ class TomlConfig(BaseConfig): - def __init__(self, *, data: str, path: Union[Path, str]): + def __init__(self, *, data: Union[bytes, str], path: Union[Path, str]): super(TomlConfig, self).__init__() self.is_empty_config = False self._parse_setting(data) @@ -23,7 +23,7 @@ def set_key(self, key, value): For now only strings are supported. We use to update the version number. """ - with open(self.path, "r") as f: + with open(self.path, "rb") as f: parser = parse(f.read()) parser["tool"]["commitizen"][key] = value @@ -31,7 +31,7 @@ def set_key(self, key, value): f.write(parser.as_string()) return self - def _parse_setting(self, data: str): + def _parse_setting(self, data: Union[bytes, str]): """We expect to have a section in pyproject looking like ``` diff --git a/commitizen/config/yaml_config.py b/commitizen/config/yaml_config.py index 510882b9b0..5d199c1929 100644 --- a/commitizen/config/yaml_config.py +++ b/commitizen/config/yaml_config.py @@ -7,7 +7,7 @@ class YAMLConfig(BaseConfig): - def __init__(self, *, data: str, path: Union[Path, str]): + def __init__(self, *, data: Union[bytes, str], path: Union[Path, str]): super(YAMLConfig, self).__init__() self.is_empty_config = False self._parse_setting(data) @@ -17,7 +17,7 @@ def init_empty_config_content(self): with open(self.path, "a") as json_file: yaml.dump({"commitizen": {}}, json_file) - def _parse_setting(self, data: str): + def _parse_setting(self, data: Union[bytes, str]): """We expect to have a section in cz.yaml looking like ``` @@ -37,7 +37,7 @@ def set_key(self, key, value): For now only strings are supported. We use to update the version number. """ - with open(self.path, "r") as yaml_file: + with open(self.path, "rb") as yaml_file: parser = yaml.load(yaml_file, Loader=yaml.FullLoader) parser["commitizen"][key] = value From d09841655e36c70fb6fd2624fc8325dfe0ab0b83 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sun, 21 Feb 2021 20:12:18 +0000 Subject: [PATCH 330/427] =?UTF-8?q?bump:=20version=202.15.0=20=E2=86=92=20?= =?UTF-8?q?2.15.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 ++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 863b358077..213cac413e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## v2.15.1 (2021-02-21) + ## v2.15.0 (2021-02-21) ## v2.14.2 (2021-02-06) diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 90c1ae3a02..b1b269754f 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.15.0" +__version__ = "2.15.1" diff --git a/pyproject.toml b/pyproject.toml index aab052f856..37765cb77c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.15.0" +version = "2.15.1" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.15.0" +version = "2.15.1" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 2756e91e3f056ba5e34cd59f681ff194ebf9bed3 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Wed, 24 Feb 2021 09:58:20 +0800 Subject: [PATCH 331/427] fix(git): fix get_commits deliminator --- commitizen/git.py | 2 +- tests/test_git.py | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/commitizen/git.py b/commitizen/git.py index e50152296b..b8fbd0715a 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -79,7 +79,7 @@ def get_commits( return [] git_commits = [] - for rev_and_commit in c.out.split(f"\n{delimiter}\n"): + for rev_and_commit in c.out.split(f"{delimiter}\n"): if not rev_and_commit: continue rev, title, author, author_email, *body_list = rev_and_commit.split("\n") diff --git a/tests/test_git.py b/tests/test_git.py index b66ae60a92..8ba2f64cb8 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -100,6 +100,43 @@ def test_get_commits_without_email(mocker): assert commits[1].title == "feat(users): add username" +def test_get_commits_without_breakline_in_each_commit(mocker): + raw_commit = ( + "ae9ba6fc5526cf478f52ef901418d85505109744\n" + "bump: version 2.13.0 → 2.14.0\n" + "GitHub Action\n" + "action@github.com\n" + "----------commit-delimiter----------\n" + "ff2f56ca844de72a9d59590831087bf5a97bac84\n" + "Merge pull request #332 from cliles/feature/271-redux\n" + "User\n" + "user@email.com\n" + "Feature/271 redux----------commit-delimiter----------\n" + "20a54bf1b82cd7b573351db4d1e8814dd0be205d\n" + "feat(#271): enable creation of annotated tags when bumping\n" + "User 2\n" + "user@email.edu\n" + "----------commit-delimiter----------\n" + ) + mocker.patch("commitizen.cmd.run", return_value=FakeCommand(out=raw_commit)) + + commits = git.get_commits() + + assert commits[0].author == "GitHub Action" + assert commits[1].author == "User" + assert commits[2].author == "User 2" + + assert commits[0].author_email == "action@github.com" + assert commits[1].author_email == "user@email.com" + assert commits[2].author_email == "user@email.edu" + + assert commits[0].title == "bump: version 2.13.0 → 2.14.0" + assert commits[1].title == "Merge pull request #332 from cliles/feature/271-redux" + assert ( + commits[2].title == "feat(#271): enable creation of annotated tags when bumping" + ) + + def test_get_tag_names_has_correct_arrow_annotation(): arrow_annotation = inspect.getfullargspec(git.get_tag_names).annotations["return"] From 311019075f49798cd6971e514c2c01d83d60d21e Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 24 Feb 2021 08:43:49 +0000 Subject: [PATCH 332/427] =?UTF-8?q?bump:=20version=202.15.1=20=E2=86=92=20?= =?UTF-8?q?2.15.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 ++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 213cac413e..e55fc64df4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## v2.15.2 (2021-02-24) + ## v2.15.1 (2021-02-21) ## v2.15.0 (2021-02-21) diff --git a/commitizen/__version__.py b/commitizen/__version__.py index b1b269754f..dd2b2a1e09 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.15.1" +__version__ = "2.15.2" diff --git a/pyproject.toml b/pyproject.toml index 37765cb77c..c565160f9a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.15.1" +version = "2.15.2" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.15.1" +version = "2.15.2" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 07d1b788f9d4c5a1ebe5cb8999f964a8d6f395a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Wed, 24 Feb 2021 10:28:54 +0100 Subject: [PATCH 333/427] docs(CHANGELOG): regenerate missing data from previous bug --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e55fc64df4..2b7b5be6b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,22 @@ + ## v2.15.2 (2021-02-24) +### Fix + +- **git**: fix get_commits deliminator + ## v2.15.1 (2021-02-21) +### Fix + +- **config**: change read mode from `r` to `rb` + ## v2.15.0 (2021-02-21) +### Feat + +- **changelog**: add support for multiline BREAKING paragraph + ## v2.14.2 (2021-02-06) ### Fix From ed06664a91551a93120ddcf3f25cda46edf1ddce Mon Sep 17 00:00:00 2001 From: 7kachika <seika850113@gmail.com> Date: Fri, 26 Feb 2021 19:15:07 +0800 Subject: [PATCH 334/427] fix: add utf-8 encode when write toml file --- commitizen/config/toml_config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commitizen/config/toml_config.py b/commitizen/config/toml_config.py index 27ab47d4e2..1950cb11d1 100644 --- a/commitizen/config/toml_config.py +++ b/commitizen/config/toml_config.py @@ -27,8 +27,8 @@ def set_key(self, key, value): parser = parse(f.read()) parser["tool"]["commitizen"][key] = value - with open(self.path, "w") as f: - f.write(parser.as_string()) + with open(self.path, "wb") as f: + f.write(parser.as_string().encode("utf-8")) return self def _parse_setting(self, data: Union[bytes, str]): From e1c1ca86dc4b6e63d7bd1ee13ec16ab3d36eeb16 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Fri, 26 Feb 2021 13:31:24 +0000 Subject: [PATCH 335/427] =?UTF-8?q?bump:=20version=202.15.2=20=E2=86=92=20?= =?UTF-8?q?2.15.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b7b5be6b1..fd49b91bc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +## v2.15.3 (2021-02-26) + +### Fix + +- add utf-8 encode when write toml file + ## v2.15.2 (2021-02-24) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index dd2b2a1e09..44e30b1266 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.15.2" +__version__ = "2.15.3" diff --git a/pyproject.toml b/pyproject.toml index c565160f9a..c6afee1864 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.15.2" +version = "2.15.3" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.15.2" +version = "2.15.3" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 80bc84a2cf0efa94309eaa8c3a740d2fac909c76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Fri, 5 Mar 2021 11:34:10 -0300 Subject: [PATCH 336/427] feat(bump): send incremental changelog to stdout and bump output to stderr --- commitizen/cli.py | 6 +++++ commitizen/commands/bump.py | 36 +++++++++++++++++++++++++++-- commitizen/out.py | 4 ++++ tests/commands/test_bump_command.py | 18 +++++++++++++++ 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index 0436155d05..a5c336f9fd 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -142,6 +142,12 @@ "help": "create annotated tag instead of lightweight one", "action": "store_true", }, + { + "name": ["--changelog-to-stdout"], + "action": "store_true", + "default": False, + "help": "Output changelog to the stdout", + }, ], }, { diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index 16c12de0ec..4f2a0d3981 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -46,6 +46,7 @@ def __init__(self, config: BaseConfig, arguments: dict): self.changelog = arguments["changelog"] or self.config.settings.get( "update_changelog_on_bump" ) + self.changelog_to_stdout = arguments["changelog_to_stdout"] self.no_verify = arguments["no_verify"] self.check_consistency = arguments["check_consistency"] @@ -110,6 +111,11 @@ def __call__(self): # noqa: C901 else: commits = git.get_commits(current_tag_version) + # If user specified changelog_to_stdout, they probably want the + # changelog to be generated as well, this is the most intuitive solution + if not self.changelog and self.changelog_to_stdout: + self.changelog = True + # No commits, there is no need to create an empty tag. # Unless we previously had a prerelease. if not commits and not current_version_instance.is_prerelease: @@ -149,12 +155,20 @@ def __call__(self): # noqa: C901 ) # Report found information - out.write( + information = ( f"{message}\n" f"tag to create: {new_tag_version}\n" f"increment detected: {increment}\n" ) + if self.changelog_to_stdout: + # When the changelog goes to stdout, we want to send + # the bump information to stderr, this way the + # changelog output can be captured + out.diagnostic(information) + else: + out.write(information) + if increment is None and new_tag_version == current_tag_version: raise NoneIncrementExit() @@ -170,6 +184,19 @@ def __call__(self): # noqa: C901 ) if self.changelog: + if self.changelog_to_stdout: + changelog_cmd = Changelog( + self.config, + { + "unreleased_version": new_tag_version, + "incremental": True, + "dry_run": True, + }, + ) + try: + changelog_cmd() + except DryRunExit: + pass changelog_cmd = Changelog( self.config, { @@ -196,7 +223,12 @@ def __call__(self): # noqa: C901 ) if c.return_code != 0: raise BumpTagFailedError(c.err) - out.success("Done!") + + # TODO: For v3 output this only as diagnostic and remove this if + if self.changelog_to_stdout: + out.diagnostic("Done!") + else: + out.success("Done!") def _get_commit_args(self): commit_args = ["-a"] diff --git a/commitizen/out.py b/commitizen/out.py index 268f02e29f..7ac5ba420b 100644 --- a/commitizen/out.py +++ b/commitizen/out.py @@ -26,3 +26,7 @@ def success(value: str): def info(value: str): message = colored(value, "blue") line(message) + + +def diagnostic(value: str): + line(value, file=sys.stderr) diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index ff4acd7a04..8508c66eee 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -414,3 +414,21 @@ def test_prevent_prerelease_when_no_increment_detected( "[NO_COMMITS_FOUND]\n" "No commits found to generate a pre-release." ) assert expected_error_message in str(excinfo.value) + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_bump_with_changelog_to_stdout_arg(mocker, capsys, changelog_path): + create_file_and_commit("feat(user): this should appear in stdout") + testargs = ["cz", "bump", "--yes", "--changelog-to-stdout"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + out, _ = capsys.readouterr() + + assert "this should appear in stdout" in out + tag_exists = git.tag_exist("0.2.0") + assert tag_exists is True + + with open(changelog_path, "r") as f: + out = f.read() + assert out.startswith("#") + assert "0.2.0" in out From ab35a0115dcaedf5d08d429c696f8a4215d65f25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Fri, 5 Mar 2021 12:03:23 -0300 Subject: [PATCH 337/427] test: correct yaml load warning --- tests/commands/test_init_command.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/commands/test_init_command.py b/tests/commands/test_init_command.py index 977e9e6a11..729950fc8a 100644 --- a/tests/commands/test_init_command.py +++ b/tests/commands/test_init_command.py @@ -116,7 +116,9 @@ def test_no_existing_pre_commit_conifg(_, default_choice, tmpdir, config): if "json" in default_choice: assert json.load(file) == EXPECTED_DICT_CONFIG elif "yaml" in default_choice: - assert yaml.load(file) == EXPECTED_DICT_CONFIG + assert ( + yaml.load(file, Loader=yaml.FullLoader) == EXPECTED_DICT_CONFIG + ) else: config_data = file.read() assert config_data == expected_config @@ -136,7 +138,9 @@ def test_empty_pre_commit_config(_, default_choice, tmpdir, config): if "json" in default_choice: assert json.load(file) == EXPECTED_DICT_CONFIG elif "yaml" in default_choice: - assert yaml.load(file) == EXPECTED_DICT_CONFIG + assert ( + yaml.load(file, Loader=yaml.FullLoader) == EXPECTED_DICT_CONFIG + ) else: config_data = file.read() assert config_data == expected_config @@ -162,7 +166,9 @@ def test_pre_commit_config_without_cz_hook(_, default_choice, tmpdir, config): if "json" in default_choice: assert json.load(file) == EXPECTED_DICT_CONFIG elif "yaml" in default_choice: - assert yaml.load(file) == EXPECTED_DICT_CONFIG + assert ( + yaml.load(file, Loader=yaml.FullLoader) == EXPECTED_DICT_CONFIG + ) else: config_data = file.read() assert config_data == expected_config @@ -184,7 +190,9 @@ def test_cz_hook_exists_in_pre_commit_config(_, default_choice, tmpdir, config): if "json" in default_choice: assert json.load(file) == EXPECTED_DICT_CONFIG elif "yaml" in default_choice: - assert yaml.load(file) == EXPECTED_DICT_CONFIG + assert ( + yaml.load(file, Loader=yaml.FullLoader) == EXPECTED_DICT_CONFIG + ) else: config_data = file.read() assert config_data == expected_config From ea372e3602ad246c760154392fc5f0cc8bfc4494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Fri, 5 Mar 2021 12:10:58 -0300 Subject: [PATCH 338/427] docs(bump): explain new flag --changelog-to-stdout --- docs/bump.md | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/docs/bump.md b/docs/bump.md index 086cfa2ea2..bf3b207cd6 100644 --- a/docs/bump.md +++ b/docs/bump.md @@ -139,7 +139,6 @@ However, it will still update `pyproject.toml` and `src/__version__.py`. To fix it, you'll first `git checkout .` to reset to the status before trying to bump and update the version in `setup.py` to `1.21.0` - ### `--local-version` Bump the local portion of the version. @@ -161,6 +160,25 @@ If `--local-version` is used, it will bump only the local version `0.1.0` and ke If `--annotated-tag` is used, commitizen will create annotated tags. Also available via configuration, in `pyproject.toml` or `.cz.toml`. +### `--changelog-to-stdout` + +If `--changelog-to-stdout` is used, the incremental changelog generated by the bump +will be sent to the stdout, and any other message generated by the bump will be +sent to stderr. + +If `--changelog` is not used with this command, it is still smart enough to +understand that the user wants to create a changelog. It is recommened to be +explicit and use `--changelog` (or the setting `update_changelog_on_bump`). + +This command is useful to "transport" the newly created changelog. +It can be sent to an auditing system, or to create a Github Release. + +Example: + +```bash +cz bump --changelog --changelog-to-stdout > body.md +``` + ## Configuration ### `tag_format` @@ -198,7 +216,7 @@ Supported variables: --- -### `version_files` * +### `version_files` \* It is used to identify the files which should be updated with the new version. It is also possible to provide a pattern for each file, separated by colons (`:`). From 3b591f02c8c0008adb57775a17ece7a9b0d6f230 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Mon, 8 Mar 2021 01:16:51 +0000 Subject: [PATCH 339/427] =?UTF-8?q?bump:=20version=202.15.3=20=E2=86=92=20?= =?UTF-8?q?2.16.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd49b91bc0..024535f0dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +## v2.16.0 (2021-03-08) + +### Feat + +- **bump**: send incremental changelog to stdout and bump output to stderr + ## v2.15.3 (2021-02-26) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 44e30b1266..8f4a351703 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.15.3" +__version__ = "2.16.0" diff --git a/pyproject.toml b/pyproject.toml index c6afee1864..82f8a88e28 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.15.3" +version = "2.16.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.15.3" +version = "2.16.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From e2c73030f94dd00a6c134a97a091325b315c158f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Mon, 8 Mar 2021 11:34:19 -0300 Subject: [PATCH 340/427] docs(tutorial/github_action): explain how to create a github release --- docs/tutorials/github_actions.md | 70 ++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/docs/tutorials/github_actions.md b/docs/tutorials/github_actions.md index aad2e8eb4f..58726afcd2 100644 --- a/docs/tutorials/github_actions.md +++ b/docs/tutorials/github_actions.md @@ -7,12 +7,12 @@ 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`. + project repository and then `Settings > Secrets > Add new secret`. 3. In your repository create a new file `.github/workflows/bumpversion.yml` -with the following content. + with the following content. !!! warning - If you use `GITHUB_TOKEN` instead of `PERSONAL_ACCESS_TOKEN`, the job won't trigger another workflow. It's like using `[skip ci]` in other CI's. +If you use `GITHUB_TOKEN` instead of `PERSONAL_ACCESS_TOKEN`, the job won't trigger another workflow. It's like using `[skip ci]` in other CI's. ```yaml name: Bump version @@ -31,17 +31,43 @@ jobs: - name: Check out uses: actions/checkout@v2 with: - token: '${{ secrets.PERSONAL_ACCESS_TOKEN }}' + token: "${{ secrets.PERSONAL_ACCESS_TOKEN }}" fetch-depth: 0 - name: Create bump and changelog uses: commitizen-tools/commitizen-action@master with: github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} - ``` Push to master and that's it. +### Creating a github release + +You can modify the previous action. + +Add the variable `changelog_increment_filename` in the `commitizen-action`, specifying +where to output the content of the changelog for the newly created version. + +And then add a step using a github action to create the release: `softprops/action-gh-release` + +The commitizen action creates an env variable called `REVISION`, containing the +newely created version. + +```yaml +- name: Create bump and changelog + uses: commitizen-tools/commitizen-action@master + with: + github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + changelog_increment_filename: body.md +- name: Release + uses: softprops/action-gh-release@v1 + with: + body_path: "body.md" + tag_name: ${{ env.REVISION }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +``` + ### Publishing a python package Once the new tag is created, triggering an automatic publish command would be desired. @@ -62,28 +88,28 @@ name: Upload Python Package on: push: tags: - - '*' # Will trigger for every tag, alternative: 'v*' + - "*" # 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: __token__ - PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }} - run: | - ./scripts/publish + - 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: __token__ + 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/commitizen-tools/commitizen/blob/master/scripts/publish) From e8955d4e36dedb7f7ab35efe0ca858b44664ae9b Mon Sep 17 00:00:00 2001 From: Omer Katz <omer.drow@gmail.com> Date: Mon, 22 Mar 2021 00:59:34 +0200 Subject: [PATCH 341/427] docs(README): correct typo --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 05bdc79a22..f930841380 100644 --- a/docs/README.md +++ b/docs/README.md @@ -177,7 +177,7 @@ See [Third-Party Commitizen Templates](third-party-commitizen.md). ### Why are `revert` and `chore` valid types in the check pattern of cz conventional_commits but not types we can select? `revert` and `chore` are added to the "pattern" in `cz check` in order to prevent backward errors, but officially they are not part of conventional commits, we are using the latest [types from Angular](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#type) (they used to but were removed). -However, you can create a customized `cz` with those extra types. (See [Customization](https://commitizen-tools.github.io/commitizen/customization/) +However, you can create a customized `cz` with those extra types. (See [Customization](https://commitizen-tools.github.io/commitizen/customization/)) See more discussion in issue [#142](https://github.com/commitizen-tools/commitizen/issues/142) and [#36](https://github.com/commitizen-tools/commitizen/issues/36) From 8902b4092a58fb498066e9e804591a73917555e8 Mon Sep 17 00:00:00 2001 From: Jairo Llopis <Yajo@users.noreply.github.com> Date: Wed, 31 Mar 2021 09:03:39 +0100 Subject: [PATCH 342/427] docs: remove duplicated file name `.cz.toml` is specified twice and gets confusing. --- docs/customization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/customization.md b/docs/customization.md index 204395ed4b..3492d8288c 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -3,7 +3,7 @@ We have two different ways to do so. ## 1. Customize in configuration file -**This is only supported when configuring through `toml` or `json` (e.g., `pyproject.toml`, `.cz.toml`, `.cz.toml`, `.cz.json`, and `cz.json`)** +**This is only supported when configuring through `toml` or `json` (e.g., `pyproject.toml`, `.cz.toml`, `.cz.json`, and `cz.json`)** The basic steps are: From cd7018ebae89b76d9174d103407d140a1dd7bf09 Mon Sep 17 00:00:00 2001 From: Jayson Reis <santosdosreis@gmail.com> Date: Sat, 20 Mar 2021 22:39:33 +0100 Subject: [PATCH 343/427] feat: Support versions on random positions --- commitizen/bump.py | 47 +++++++++++++--------- tests/test_bump_update_version_in_files.py | 36 +++++++++++++++++ 2 files changed, 64 insertions(+), 19 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index ccb1257e7d..2d0c7aee83 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -150,26 +150,25 @@ def update_version_in_files( """ # TODO: separate check step and write step for location in files: - filepath, *regexes = location.split(":", maxsplit=1) + filepath, *regexes = location.split(":") regex = regexes[0] if regexes else None - - # Read in the file - file_content = [] current_version_found = False - with open(filepath, "r") as version_file: - for line in version_file: - if regex: - match = re.search(regex, line) - if not match: - file_content.append(line) - continue - - # Replace the target string - if current_version in line: - current_version_found = True - file_content.append(line.replace(current_version, new_version)) - else: - file_content.append(line) + + version_file = open(filepath, "r").read() + match = regex and re.search(regex, version_file, re.MULTILINE) + if match: + left = version_file[: match.end()] + right = version_file[match.end() :] + line_break = _get_line_break_position(right) + middle = right[:line_break] + current_version_found = current_version in middle + right = right[line_break:] + version_file = left + middle.replace(current_version, new_version) + right + + if not regex: + current_version_regex = _version_to_regex(current_version) + current_version_found = current_version_regex.search(version_file) and True + version_file = current_version_regex.sub(new_version, version_file) if check_consistency and not current_version_found: raise CurrentVersionNotFoundError( @@ -180,7 +179,17 @@ def update_version_in_files( # Write the file out again with open(filepath, "w") as file: - file.write("".join(file_content)) + file.write("".join(version_file)) + + +def _get_line_break_position(text: str) -> int: + position = text.find("\n") + return max(position, 0) + + +def _version_to_regex(version: str): + clean_regex = version.replace(".", r"\.").replace("+", r"\+") + return re.compile(f"\\b{clean_regex}\\b") def create_tag(version: Union[Version, str], tag_format: Optional[str] = None): diff --git a/tests/test_bump_update_version_in_files.py b/tests/test_bump_update_version_in_files.py index 26a6ad677a..cadf4af8d2 100644 --- a/tests/test_bump_update_version_in_files.py +++ b/tests/test_bump_update_version_in_files.py @@ -1,3 +1,5 @@ +import re + import pytest from commitizen import bump @@ -33,6 +35,21 @@ } """ +# The order cannot be guaranteed here +CARGO_LOCK = """ +[[package]] +name = "textwrap" +version = "1.2.3" + +[[package]] +name = "there-i-fixed-it" +version = "1.2.3" + +[[package]] +name = "other-project" +version = "1.2.3" +""" + @pytest.fixture(scope="function") def commitizen_config_file(tmpdir): @@ -55,6 +72,13 @@ def inconsistent_python_version_file(tmpdir): return str(tmp_file) +@pytest.fixture(scope="function") +def random_location_version_file(tmpdir): + tmp_file = tmpdir.join("Cargo.lock") + tmp_file.write(CARGO_LOCK) + return str(tmp_file) + + @pytest.fixture(scope="function") def version_repeated_file(tmpdir): tmp_file = tmpdir.join("package.json") @@ -90,6 +114,18 @@ def test_partial_update_of_file(version_repeated_file): assert old_version in data +def test_random_location(random_location_version_file): + old_version = "1.2.3" + new_version = "2.0.0" + location = f"{random_location_version_file}:there-i-fixed-it.+\nversion" + + bump.update_version_in_files(old_version, new_version, [location]) + with open(random_location_version_file, "r") as f: + data = f.read() + assert len(re.findall(old_version, data)) == 2 + assert len(re.findall(new_version, data)) == 1 + + def test_file_version_inconsistent_error( commitizen_config_file, inconsistent_python_version_file, version_repeated_file ): From 8689546f84d4d5a3f9ff7a747207b3601baa92a3 Mon Sep 17 00:00:00 2001 From: Jayson Reis <santosdosreis@gmail.com> Date: Wed, 31 Mar 2021 17:45:14 +0200 Subject: [PATCH 344/427] chore: Fix CR questions --- commitizen/bump.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index 2d0c7aee83..b91639289f 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -154,7 +154,9 @@ def update_version_in_files( regex = regexes[0] if regexes else None current_version_found = False - version_file = open(filepath, "r").read() + with open(filepath, "r") as f: + version_file = f.read() + match = regex and re.search(regex, version_file, re.MULTILINE) if match: left = version_file[: match.end()] @@ -167,7 +169,7 @@ def update_version_in_files( if not regex: current_version_regex = _version_to_regex(current_version) - current_version_found = current_version_regex.search(version_file) and True + current_version_found = bool(current_version_regex.search(version_file)) version_file = current_version_regex.sub(new_version, version_file) if check_consistency and not current_version_found: From 32916abd2210e8c2c8852b42f51fcbbb01181f4b Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Fri, 2 Apr 2021 01:27:36 +0000 Subject: [PATCH 345/427] =?UTF-8?q?bump:=20version=202.16.0=20=E2=86=92=20?= =?UTF-8?q?2.17.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 024535f0dc..913780b54f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +## v2.17.0 (2021-04-02) + +### Feat + +- Support versions on random positions + ## v2.16.0 (2021-03-08) ### Feat diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 8f4a351703..a6b62ff3b2 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.16.0" +__version__ = "2.17.0" diff --git a/pyproject.toml b/pyproject.toml index 82f8a88e28..07676c21ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.16.0" +version = "2.17.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.16.0" +version = "2.17.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From b8bc9522a60149f744835da7b347c9397f9edf71 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Thu, 8 Apr 2021 17:59:33 +0800 Subject: [PATCH 346/427] fix(commands/init): fix toml config format error #367 --- commitizen/config/toml_config.py | 16 +++++++++++++--- tests/commands/test_init_command.py | 1 + tests/test_conf.py | 4 ++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/commitizen/config/toml_config.py b/commitizen/config/toml_config.py index 1950cb11d1..284e8d41b5 100644 --- a/commitizen/config/toml_config.py +++ b/commitizen/config/toml_config.py @@ -1,7 +1,8 @@ +import os from pathlib import Path from typing import Union -from tomlkit import exceptions, parse +from tomlkit import exceptions, parse, table from .base_config import BaseConfig @@ -14,8 +15,17 @@ def __init__(self, *, data: Union[bytes, str], path: Union[Path, str]): self.add_path(path) def init_empty_config_content(self): - with open(self.path, "a") as toml_file: - toml_file.write("[tool.commitizen]") + if os.path.isfile(self.path): + with open(self.path, "rb") as input_toml_file: + parser = parse(input_toml_file.read()) + else: + parser = parse("") + + with open(self.path, "wb") as output_toml_file: + if parser.get("tool") is None: + parser["tool"] = table() + parser["tool"]["commitizen"] = table() + output_toml_file.write(parser.as_string().encode("utf-8")) def set_key(self, key, value): """Set or update a key in the conf. diff --git a/tests/commands/test_init_command.py b/tests/commands/test_init_command.py index 729950fc8a..e7f2c00edf 100644 --- a/tests/commands/test_init_command.py +++ b/tests/commands/test_init_command.py @@ -25,6 +25,7 @@ def ask(self): } expected_config = ( + "[tool]\n" "[tool.commitizen]\n" 'name = "cz_conventional_commits"\n' 'version = "0.0.1"\n' diff --git a/tests/test_conf.py b/tests/test_conf.py index ea7b3a3c98..f05603cfe4 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -132,7 +132,7 @@ def test_init_empty_config_content(self, tmpdir): toml_config.init_empty_config_content() with open(path, "r") as toml_file: - assert toml_file.read() == "[tool.commitizen]" + assert toml_file.read() == "[tool]\n[tool.commitizen]\n" def test_init_empty_config_content_with_existing_content(self, tmpdir): existing_content = "[tool.black]\n" "line-length = 88\n" @@ -143,7 +143,7 @@ def test_init_empty_config_content_with_existing_content(self, tmpdir): toml_config.init_empty_config_content() with open(path, "r") as toml_file: - assert toml_file.read() == existing_content + "[tool.commitizen]" + assert toml_file.read() == existing_content + "\n[tool.commitizen]\n" class TestJsonConfig: From b541addb23cd4b42c78f2c7d22ba48c70763314f Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 8 Apr 2021 10:42:45 +0000 Subject: [PATCH 347/427] =?UTF-8?q?bump:=20version=202.17.0=20=E2=86=92=20?= =?UTF-8?q?2.17.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 913780b54f..5089b2233c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +## v2.17.1 (2021-04-08) + +### Fix + +- **commands/init**: fix toml config format error + ## v2.17.0 (2021-04-02) ### Feat diff --git a/commitizen/__version__.py b/commitizen/__version__.py index a6b62ff3b2..1976873631 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.17.0" +__version__ = "2.17.1" diff --git a/pyproject.toml b/pyproject.toml index 07676c21ea..9430095da0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.17.0" +version = "2.17.1" tag_format = "v$version" version_files = [ "pyproject.toml:version", From 5b3c9e2fb2289eadfee4f0b12560ff6cf28d8514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Fri, 9 Apr 2021 18:36:01 +0200 Subject: [PATCH 348/427] fix(wip): add test for current breaking change --- tests/test_bump_update_version_in_files.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_bump_update_version_in_files.py b/tests/test_bump_update_version_in_files.py index cadf4af8d2..aebd87996f 100644 --- a/tests/test_bump_update_version_in_files.py +++ b/tests/test_bump_update_version_in_files.py @@ -126,6 +126,18 @@ def test_random_location(random_location_version_file): assert len(re.findall(new_version, data)) == 1 +def test_duplicates_are_change_with_no_regex(random_location_version_file): + old_version = "1.2.3" + new_version = "2.0.0" + location = f"{random_location_version_file}:version" + + bump.update_version_in_files(old_version, new_version, [location]) + with open(random_location_version_file, "r") as f: + data = f.read() + assert len(re.findall(old_version, data)) == 0 + assert len(re.findall(new_version, data)) == 3 + + def test_file_version_inconsistent_error( commitizen_config_file, inconsistent_python_version_file, version_repeated_file ): From f4cbc35fd72c75bf6782daf7066a2f3d5e10019e Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 10 Apr 2021 15:55:26 +0800 Subject: [PATCH 349/427] fix(bump): replace all occurances that match regex --- commitizen/bump.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index b91639289f..5e2709255d 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -157,15 +157,17 @@ def update_version_in_files( with open(filepath, "r") as f: version_file = f.read() - match = regex and re.search(regex, version_file, re.MULTILINE) - if match: - left = version_file[: match.end()] - right = version_file[match.end() :] - line_break = _get_line_break_position(right) - middle = right[:line_break] - current_version_found = current_version in middle - right = right[line_break:] - version_file = left + middle.replace(current_version, new_version) + right + if regex: + for match in re.finditer(regex, version_file, re.MULTILINE): + left = version_file[: match.end()] + right = version_file[match.end() :] + line_break = _get_line_break_position(right) + middle = right[:line_break] + current_version_found = current_version in middle + right = right[line_break:] + version_file = ( + left + middle.replace(current_version, new_version) + right + ) if not regex: current_version_regex = _version_to_regex(current_version) From 2b64adf53f3ddcf04258eaa67b6270348a46cd0a Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Sat, 10 Apr 2021 08:03:56 +0000 Subject: [PATCH 350/427] =?UTF-8?q?bump:=20version=202.17.1=20=E2=86=92=20?= =?UTF-8?q?2.17.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 7 +++++++ commitizen/__version__.py | 2 +- pyproject.toml | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5089b2233c..84e98ac549 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,11 @@ +## v2.17.2 (2021-04-10) + +### Fix + +- **bump**: replace all occurances that match regex +- **wip**: add test for current breaking change + ## v2.17.1 (2021-04-08) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 1976873631..4d144b2359 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.17.1" +__version__ = "2.17.2" diff --git a/pyproject.toml b/pyproject.toml index 9430095da0..9302ba555a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.17.1" +version = "2.17.2" tag_format = "v$version" version_files = [ "pyproject.toml:version", From 6be8d931a87d0dee8083c9c7b51f939b89033f04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 10 Apr 2021 10:10:00 +0200 Subject: [PATCH 351/427] ci: update package version in pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9302ba555a..212075517d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.17.0" +version = "2.17.2" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 127d1b041648a7ba24eadbbf6a4068e2a599b6ca Mon Sep 17 00:00:00 2001 From: Jayson Reis <santosdosreis@gmail.com> Date: Sat, 17 Apr 2021 19:45:37 +0200 Subject: [PATCH 352/427] fix: fix multiple versions bumps when version changes the string size --- commitizen/bump.py | 38 ++++++++++++------- tests/test_bump_update_version_in_files.py | 43 ++++++++++++++++++++++ 2 files changed, 68 insertions(+), 13 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index 5e2709255d..e6c9089bef 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -152,24 +152,15 @@ def update_version_in_files( for location in files: filepath, *regexes = location.split(":") regex = regexes[0] if regexes else None - current_version_found = False with open(filepath, "r") as f: version_file = f.read() if regex: - for match in re.finditer(regex, version_file, re.MULTILINE): - left = version_file[: match.end()] - right = version_file[match.end() :] - line_break = _get_line_break_position(right) - middle = right[:line_break] - current_version_found = current_version in middle - right = right[line_break:] - version_file = ( - left + middle.replace(current_version, new_version) + right - ) - - if not regex: + current_version_found, version_file = _bump_with_regex( + version_file, current_version, new_version, regex + ) + else: current_version_regex = _version_to_regex(current_version) current_version_found = bool(current_version_regex.search(version_file)) version_file = current_version_regex.sub(new_version, version_file) @@ -186,6 +177,27 @@ def update_version_in_files( file.write("".join(version_file)) +def _bump_with_regex(version_file_contents, current_version, new_version, regex): + current_version_found = False + # Bumping versions that change the string length move the offset on the file contents as finditer keeps a + # reference to the initial string that was used and calling search many times would lead in infinite loops + # e.g.: 1.1.9 -> 1.1.20 + offset = 0 + for match in re.finditer(regex, version_file_contents, re.MULTILINE): + left = version_file_contents[: match.end() + offset] + right = version_file_contents[match.end() + offset :] + line_break = _get_line_break_position(right) + middle = right[:line_break] + current_version_found_in_block = current_version in middle + offset += len(new_version) - len(current_version) + current_version_found |= current_version_found_in_block + right = right[line_break:] + version_file_contents = ( + left + middle.replace(current_version, new_version) + right + ) + return current_version_found, version_file_contents + + def _get_line_break_position(text: str) -> int: position = text.find("\n") return max(position, 0) diff --git a/tests/test_bump_update_version_in_files.py b/tests/test_bump_update_version_in_files.py index aebd87996f..0e0e8f5c30 100644 --- a/tests/test_bump_update_version_in_files.py +++ b/tests/test_bump_update_version_in_files.py @@ -50,6 +50,9 @@ version = "1.2.3" """ +MULTIPLE_VERSIONS_INCREASE_STRING = 'version = "1.2.9"\n' * 30 +MULTIPLE_VERSIONS_REDUCE_STRING = 'version = "1.2.10"\n' * 30 + @pytest.fixture(scope="function") def commitizen_config_file(tmpdir): @@ -86,6 +89,20 @@ def version_repeated_file(tmpdir): return str(tmp_file) +@pytest.fixture(scope="function") +def multiple_versions_increase_string(tmpdir): + tmp_file = tmpdir.join("anyfile") + tmp_file.write(MULTIPLE_VERSIONS_INCREASE_STRING) + return str(tmp_file) + + +@pytest.fixture(scope="function") +def multiple_versions_reduce_string(tmpdir): + tmp_file = tmpdir.join("anyfile") + tmp_file.write(MULTIPLE_VERSIONS_REDUCE_STRING) + return str(tmp_file) + + @pytest.fixture(scope="function") def version_files(commitizen_config_file, python_version_file, version_repeated_file): return [commitizen_config_file, python_version_file, version_repeated_file] @@ -138,6 +155,32 @@ def test_duplicates_are_change_with_no_regex(random_location_version_file): assert len(re.findall(new_version, data)) == 3 +def test_version_bump_increase_string_length(multiple_versions_increase_string): + old_version = "1.2.9" + new_version = "1.2.10" + version_bump_change_string_size( + multiple_versions_increase_string, old_version, new_version + ) + + +def test_version_bump_reduce_string_length(multiple_versions_reduce_string): + old_version = "1.2.10" + new_version = "2.0.0" + version_bump_change_string_size( + multiple_versions_reduce_string, old_version, new_version + ) + + +def version_bump_change_string_size(filename, old_version, new_version): + location = f"{filename}:version" + + bump.update_version_in_files(old_version, new_version, [location]) + with open(filename, "r") as f: + data = f.read() + assert len(re.findall(old_version, data)) == 0 + assert len(re.findall(new_version, data)) == 30 + + def test_file_version_inconsistent_error( commitizen_config_file, inconsistent_python_version_file, version_repeated_file ): From 8a354571319b02bf2be42a0ee648d0f925c8d58f Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Mon, 19 Apr 2021 00:51:27 +0000 Subject: [PATCH 353/427] =?UTF-8?q?bump:=20version=202.17.2=20=E2=86=92=20?= =?UTF-8?q?2.17.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84e98ac549..e83f1770fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +## v2.17.3 (2021-04-19) + +### Fix + +- fix multiple versions bumps when version changes the string size + ## v2.17.2 (2021-04-10) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 4d144b2359..58f5db05c9 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.17.2" +__version__ = "2.17.3" diff --git a/pyproject.toml b/pyproject.toml index 212075517d..11a9543f97 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.17.2" +version = "2.17.3" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.17.2" +version = "2.17.3" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 8638512bfc5018d07a90851889b30a99bb9007ce Mon Sep 17 00:00:00 2001 From: Peter Slump <peter@peakfijn.nl> Date: Thu, 22 Apr 2021 13:39:37 +0200 Subject: [PATCH 354/427] fix: version update in a docker-compose.yaml file --- commitizen/bump.py | 2 +- tests/test_bump_update_version_in_files.py | 30 ++++++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index e6c9089bef..3a93575941 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -205,7 +205,7 @@ def _get_line_break_position(text: str) -> int: def _version_to_regex(version: str): clean_regex = version.replace(".", r"\.").replace("+", r"\+") - return re.compile(f"\\b{clean_regex}\\b") + return re.compile(f"{clean_regex}") def create_tag(version: Union[Version, str], tag_format: Optional[str] = None): diff --git a/tests/test_bump_update_version_in_files.py b/tests/test_bump_update_version_in_files.py index 0e0e8f5c30..4b0cf19a44 100644 --- a/tests/test_bump_update_version_in_files.py +++ b/tests/test_bump_update_version_in_files.py @@ -50,6 +50,15 @@ version = "1.2.3" """ +DOCKER_COMPOSE = """ +version: "3.3" + +services: + app: + image: my-repo/my-container:v1.2.3 + command: my-command +""" + MULTIPLE_VERSIONS_INCREASE_STRING = 'version = "1.2.9"\n' * 30 MULTIPLE_VERSIONS_REDUCE_STRING = 'version = "1.2.10"\n' * 30 @@ -104,8 +113,25 @@ def multiple_versions_reduce_string(tmpdir): @pytest.fixture(scope="function") -def version_files(commitizen_config_file, python_version_file, version_repeated_file): - return [commitizen_config_file, python_version_file, version_repeated_file] +def docker_compose_file(tmpdir): + tmp_file = tmpdir.join("docker-compose.yaml") + tmp_file.write(DOCKER_COMPOSE) + return str(tmp_file) + + +@pytest.fixture(scope="function") +def version_files( + commitizen_config_file, + python_version_file, + version_repeated_file, + docker_compose_file, +): + return [ + commitizen_config_file, + python_version_file, + version_repeated_file, + docker_compose_file, + ] def test_update_version_in_files(version_files): From ba94e3f90e2df2a80c9946968e1ff15696584b79 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 22 Apr 2021 12:02:06 +0000 Subject: [PATCH 355/427] =?UTF-8?q?bump:=20version=202.17.3=20=E2=86=92=20?= =?UTF-8?q?2.17.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e83f1770fd..e993ab1142 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +## v2.17.4 (2021-04-22) + +### Fix + +- version update in a docker-compose.yaml file + ## v2.17.3 (2021-04-19) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 58f5db05c9..de06464cf1 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.17.3" +__version__ = "2.17.4" diff --git a/pyproject.toml b/pyproject.toml index 11a9543f97..fff7f46898 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.17.3" +version = "2.17.4" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.17.3" +version = "2.17.4" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From ff45677bad756270aa5b18501b8a980d1b0e871a Mon Sep 17 00:00:00 2001 From: Trim21 <github@trim21.me> Date: Thu, 6 May 2021 03:39:30 +0800 Subject: [PATCH 356/427] fix docs typo --- docs/changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.md b/docs/changelog.md index 41a5615d6c..f5dd5fd5e3 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -88,7 +88,7 @@ By introducing `unreleased_version` you can prevent this situation. Before bumping you can run: ```bash -cz changelog --unreleased_version="v1.0.0" +cz changelog --unreleased-version="v1.0.0" ``` Remember to use the tag instead of the raw version number From 6082b647e1f6c1e94d03f75e66247a54ab93630c Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 6 May 2021 01:48:47 +0000 Subject: [PATCH 357/427] =?UTF-8?q?bump:=20version=202.17.4=20=E2=86=92=20?= =?UTF-8?q?2.17.5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 ++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e993ab1142..33e4c7d403 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ +## v2.17.5 (2021-05-06) + ## v2.17.4 (2021-04-22) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index de06464cf1..b33b8dc03b 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.17.4" +__version__ = "2.17.5" diff --git a/pyproject.toml b/pyproject.toml index fff7f46898..9922259f89 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.17.4" +version = "2.17.5" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.17.4" +version = "2.17.5" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 881ad02adb1945b03306aa1f2339f98d5d977714 Mon Sep 17 00:00:00 2001 From: Sonny V <sonny@softllama.net> Date: Thu, 6 May 2021 10:27:08 +0200 Subject: [PATCH 358/427] fix(cz/conventional_commits): optionally expect '!' right before ':' in schema_pattern Closes: #381 --- commitizen/cz/conventional_commits/conventional_commits.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index 7d5c27570c..6ac62d5ec1 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -178,8 +178,8 @@ def schema(self) -> str: def schema_pattern(self) -> str: PATTERN = ( - r"(build|ci|docs|feat|fix|perf|refactor|style|test|chore|revert|bump)!?" - r"(\(\S+\))?:(\s.*)" + r"(build|ci|docs|feat|fix|perf|refactor|style|test|chore|revert|bump)" + r"(\(\S+\))?!?:(\s.*)" ) return PATTERN From ba58b22e1f44b9a953dc12fd2132535b35f7568c Mon Sep 17 00:00:00 2001 From: Sonny V <sonny@softllama.net> Date: Thu, 6 May 2021 11:02:26 +0200 Subject: [PATCH 359/427] test(cz/conventional_commits): test check command and process_commit with conventional commits --- tests/commands/test_check_command.py | 12 ++++++++++-- tests/test_cz_conventional_commits.py | 22 +++++++++++++++++++--- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/tests/commands/test_check_command.py b/tests/commands/test_check_command.py index df54c1234e..7377a8a388 100644 --- a/tests/commands/test_check_command.py +++ b/tests/commands/test_check_command.py @@ -124,12 +124,19 @@ def test_check_conventional_commit_succeeds(mocker, capsys): assert "Commit validation: successful!" in out -def test_check_no_conventional_commit(config, mocker, tmpdir): +@pytest.mark.parametrize( + "commit_msg", + ( + "feat!(lang): removed polish language", + "no conventional commit", + ), +) +def test_check_no_conventional_commit(commit_msg, config, mocker, tmpdir): with pytest.raises(InvalidCommitMessageError): error_mock = mocker.patch("commitizen.out.error") tempfile = tmpdir.join("temp_commit_file") - tempfile.write("no conventional commit") + tempfile.write(commit_msg) check_cmd = commands.Check( config=config, arguments={"commit_msg_file": tempfile} @@ -141,6 +148,7 @@ def test_check_no_conventional_commit(config, mocker, tmpdir): @pytest.mark.parametrize( "commit_msg", ( + "feat(lang)!: removed polish language", "feat(lang): added polish language", "feat: add polish language", "bump: 0.0.1 -> 1.0.0", diff --git a/tests/test_cz_conventional_commits.py b/tests/test_cz_conventional_commits.py index 62eef11a19..2a239cafee 100644 --- a/tests/test_cz_conventional_commits.py +++ b/tests/test_cz_conventional_commits.py @@ -132,7 +132,23 @@ def test_info(config): assert isinstance(info, str) -def test_process_commit(config): +@pytest.mark.parametrize(("commit_message", "expected_message"), + [ + ( + "test(test_scope): this is test msg", + "this is test msg", + ), + ( + "test(test_scope)!: this is test msg", + "this is test msg", + ), + ( + "test!(test_scope): this is test msg", + "", + ), + ] +) +def test_process_commit(commit_message, expected_message, config): conventional_commits = ConventionalCommitsCz(config) - message = conventional_commits.process_commit("test(test_scope): this is test msg") - assert message == "this is test msg" + message = conventional_commits.process_commit(commit_message) + assert message == expected_message From e1074115a1eae62326f5e998ed52692b956f8163 Mon Sep 17 00:00:00 2001 From: Sonny V <sonny@softllama.net> Date: Thu, 6 May 2021 11:03:38 +0200 Subject: [PATCH 360/427] style(tests): format tests --- tests/commands/test_check_command.py | 6 +----- tests/test_cz_conventional_commits.py | 20 ++++++-------------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/tests/commands/test_check_command.py b/tests/commands/test_check_command.py index 7377a8a388..ac545e3a6a 100644 --- a/tests/commands/test_check_command.py +++ b/tests/commands/test_check_command.py @@ -125,11 +125,7 @@ def test_check_conventional_commit_succeeds(mocker, capsys): @pytest.mark.parametrize( - "commit_msg", - ( - "feat!(lang): removed polish language", - "no conventional commit", - ), + "commit_msg", ("feat!(lang): removed polish language", "no conventional commit",), ) def test_check_no_conventional_commit(commit_msg, config, mocker, tmpdir): with pytest.raises(InvalidCommitMessageError): diff --git a/tests/test_cz_conventional_commits.py b/tests/test_cz_conventional_commits.py index 2a239cafee..e43284a121 100644 --- a/tests/test_cz_conventional_commits.py +++ b/tests/test_cz_conventional_commits.py @@ -132,21 +132,13 @@ def test_info(config): assert isinstance(info, str) -@pytest.mark.parametrize(("commit_message", "expected_message"), +@pytest.mark.parametrize( + ("commit_message", "expected_message"), [ - ( - "test(test_scope): this is test msg", - "this is test msg", - ), - ( - "test(test_scope)!: this is test msg", - "this is test msg", - ), - ( - "test!(test_scope): this is test msg", - "", - ), - ] + ("test(test_scope): this is test msg", "this is test msg",), + ("test(test_scope)!: this is test msg", "this is test msg",), + ("test!(test_scope): this is test msg", "",), + ], ) def test_process_commit(commit_message, expected_message, config): conventional_commits = ConventionalCommitsCz(config) From aa0debe9ae5939afb54de5f26c7f0c395894e330 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 6 May 2021 09:21:16 +0000 Subject: [PATCH 361/427] =?UTF-8?q?bump:=20version=202.17.5=20=E2=86=92=20?= =?UTF-8?q?2.17.6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33e4c7d403..167c010b7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +## v2.17.6 (2021-05-06) + +### Fix + +- **cz/conventional_commits**: optionally expect '!' right before ':' in schema_pattern + ## v2.17.5 (2021-05-06) ## v2.17.4 (2021-04-22) diff --git a/commitizen/__version__.py b/commitizen/__version__.py index b33b8dc03b..a4d4630238 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.17.5" +__version__ = "2.17.6" diff --git a/pyproject.toml b/pyproject.toml index 9922259f89..ee8a8622bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.17.5" +version = "2.17.6" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.17.5" +version = "2.17.6" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From b7741290513eb97c9f3fd031942f319b985a6364 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Tue, 25 May 2021 19:33:47 +0800 Subject: [PATCH 362/427] test(bump): add test cast that fails to bump correctly #383 --- tests/test_bump_update_version_in_files.py | 49 ++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/test_bump_update_version_in_files.py b/tests/test_bump_update_version_in_files.py index 4b0cf19a44..5d022db50d 100644 --- a/tests/test_bump_update_version_in_files.py +++ b/tests/test_bump_update_version_in_files.py @@ -59,6 +59,36 @@ command: my-command """ +MULTIPLE_VERSIONS_TO_UPDATE_POETRY_LOCK = """ +[[package]] +name = "to-update-1" +version = "1.2.9" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "to-update-2" +version = "1.2.9" +""" + MULTIPLE_VERSIONS_INCREASE_STRING = 'version = "1.2.9"\n' * 30 MULTIPLE_VERSIONS_REDUCE_STRING = 'version = "1.2.10"\n' * 30 @@ -119,6 +149,13 @@ def docker_compose_file(tmpdir): return str(tmp_file) +@pytest.fixture(scope="function") +def multiple_versions_to_update_poetry_lock(tmpdir): + tmp_file = tmpdir.join("pyproject.toml") + tmp_file.write(MULTIPLE_VERSIONS_TO_UPDATE_POETRY_LOCK) + return str(tmp_file) + + @pytest.fixture(scope="function") def version_files( commitizen_config_file, @@ -228,3 +265,15 @@ def test_file_version_inconsistent_error( "version_files are possibly inconsistent." ) assert expected_msg in str(excinfo.value) + + +def test_multiplt_versions_to_bump(multiple_versions_to_update_poetry_lock): + old_version = "1.2.9" + new_version = "1.2.10" + location = f"{multiple_versions_to_update_poetry_lock}:version" + + bump.update_version_in_files(old_version, new_version, [location]) + with open(multiple_versions_to_update_poetry_lock, "r") as f: + data = f.read() + assert len(re.findall(old_version, data)) == 0 + assert len(re.findall(new_version, data)) == 2 From 20d0629a84f54c9f66ef882b230a4e24e3cc5f30 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Tue, 25 May 2021 19:40:15 +0800 Subject: [PATCH 363/427] fix(bump): fix offset error due to partially match for examply, if what we want to bump is "version = 1.2.9", we still lookup up "version = 2.0.0" and changed the offset this is fixed by changing offset only when matching is found #383 --- commitizen/bump.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index 3a93575941..a4714322e0 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -188,13 +188,13 @@ def _bump_with_regex(version_file_contents, current_version, new_version, regex) right = version_file_contents[match.end() + offset :] line_break = _get_line_break_position(right) middle = right[:line_break] - current_version_found_in_block = current_version in middle - offset += len(new_version) - len(current_version) - current_version_found |= current_version_found_in_block - right = right[line_break:] - version_file_contents = ( - left + middle.replace(current_version, new_version) + right - ) + if current_version in middle: + offset += len(new_version) - len(current_version) + current_version_found = True + right = right[line_break:] + version_file_contents = ( + left + middle.replace(current_version, new_version) + right + ) return current_version_found, version_file_contents From 45b3566dfd33be08ed5dd76dcb130c7c71529ba1 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Tue, 25 May 2021 19:44:43 +0800 Subject: [PATCH 364/427] build(poetry): add pytest-regression as dev dependency --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index ee8a8622bb..b344305706 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,6 +70,7 @@ isort = "^5.7.0" freezegun = "^0.3.15" pydocstyle = "^5.0.2" pre-commit = "^2.6.0" +pytest-regressions = "^2.2.0" [tool.poetry.scripts] cz = "commitizen.cli:main" From 39872992b9b47cbad4e7b1daac7f1ff4bb804b76 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Tue, 25 May 2021 19:45:08 +0800 Subject: [PATCH 365/427] test(bump): refactor test_multiplt_versions_to_bump through file_regression --- tests/test_bump_update_version_in_files.py | 8 +++--- .../test_multiplt_versions_to_bump.toml | 28 +++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 tests/test_bump_update_version_in_files/test_multiplt_versions_to_bump.toml diff --git a/tests/test_bump_update_version_in_files.py b/tests/test_bump_update_version_in_files.py index 5d022db50d..0daa2ecb22 100644 --- a/tests/test_bump_update_version_in_files.py +++ b/tests/test_bump_update_version_in_files.py @@ -267,13 +267,13 @@ def test_file_version_inconsistent_error( assert expected_msg in str(excinfo.value) -def test_multiplt_versions_to_bump(multiple_versions_to_update_poetry_lock): +def test_multiplt_versions_to_bump( + multiple_versions_to_update_poetry_lock, file_regression +): old_version = "1.2.9" new_version = "1.2.10" location = f"{multiple_versions_to_update_poetry_lock}:version" bump.update_version_in_files(old_version, new_version, [location]) with open(multiple_versions_to_update_poetry_lock, "r") as f: - data = f.read() - assert len(re.findall(old_version, data)) == 0 - assert len(re.findall(new_version, data)) == 2 + file_regression.check(f.read(), extension=".toml") diff --git a/tests/test_bump_update_version_in_files/test_multiplt_versions_to_bump.toml b/tests/test_bump_update_version_in_files/test_multiplt_versions_to_bump.toml new file mode 100644 index 0000000000..d5e8bf082f --- /dev/null +++ b/tests/test_bump_update_version_in_files/test_multiplt_versions_to_bump.toml @@ -0,0 +1,28 @@ + +[[package]] +name = "to-update-1" +version = "1.2.10" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "to-update-2" +version = "1.2.10" From a36063b3e8756b7ff2248b1487d4889e7024a840 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Tue, 25 May 2021 23:11:33 +0800 Subject: [PATCH 366/427] style(config): ignore TomlConfig._parse_setting type annotation --- commitizen/config/toml_config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/commitizen/config/toml_config.py b/commitizen/config/toml_config.py index 284e8d41b5..b5b7f7b2a1 100644 --- a/commitizen/config/toml_config.py +++ b/commitizen/config/toml_config.py @@ -49,8 +49,8 @@ def _parse_setting(self, data: Union[bytes, str]): name = "cz_conventional_commits" ``` """ - doc = parse(data) + doc = parse(data) # type: ignore try: - self.settings.update(doc["tool"]["commitizen"]) + self.settings.update(doc["tool"]["commitizen"]) # type: ignore except exceptions.NonExistentKey: self.is_empty_config = True From dcb18bbf71e35312aa5e0e64295b1fc2b3a0008a Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Wed, 26 May 2021 15:49:30 +0800 Subject: [PATCH 367/427] test(bump_update_verison_in_files): refactor test cases through pytest-regression --- .pre-commit-config.yaml | 1 + commitizen/bump.py | 2 +- tests/test_bump_update_version_in_files.py | 163 +++++------------- ...t_duplicates_are_change_with_no_regex.lock | 11 ++ .../test_multiplt_versions_to_bump.toml | 1 - .../test_partial_update_of_file.json | 7 + .../test_random_location.lock | 11 ++ .../test_update_version_in_files.txt | 20 +++ ...st_version_bump_increase_string_length.txt | 30 ++++ ...test_version_bump_reduce_string_length.txt | 30 ++++ .../inconsistent_version.py | 4 + ...multiple_versions_to_update_pyproject.toml | 27 +++ .../repeated_version_number.json | 7 + tests/testing_version_files/sample_cargo.lock | 11 ++ .../sample_docker_compose.yaml | 6 + .../sample_pyproject.toml | 3 + tests/testing_version_files/sample_version.py | 4 + 17 files changed, 213 insertions(+), 125 deletions(-) create mode 100644 tests/test_bump_update_version_in_files/test_duplicates_are_change_with_no_regex.lock create mode 100644 tests/test_bump_update_version_in_files/test_partial_update_of_file.json create mode 100644 tests/test_bump_update_version_in_files/test_random_location.lock create mode 100644 tests/test_bump_update_version_in_files/test_update_version_in_files.txt create mode 100644 tests/test_bump_update_version_in_files/test_version_bump_increase_string_length.txt create mode 100644 tests/test_bump_update_version_in_files/test_version_bump_reduce_string_length.txt create mode 100644 tests/testing_version_files/inconsistent_version.py create mode 100644 tests/testing_version_files/multiple_versions_to_update_pyproject.toml create mode 100644 tests/testing_version_files/repeated_version_number.json create mode 100644 tests/testing_version_files/sample_cargo.lock create mode 100644 tests/testing_version_files/sample_docker_compose.yaml create mode 100644 tests/testing_version_files/sample_pyproject.toml create mode 100644 tests/testing_version_files/sample_version.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 36bbcfb646..6ecfdc2041 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,6 +5,7 @@ repos: hooks: - id: check-vcs-permalinks - id: end-of-file-fixer + exclude: "tests/test_*/*" - id: trailing-whitespace args: [--markdown-linebreak-ext=md] - id: debug-statements diff --git a/commitizen/bump.py b/commitizen/bump.py index a4714322e0..c4fbadc07c 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -188,10 +188,10 @@ def _bump_with_regex(version_file_contents, current_version, new_version, regex) right = version_file_contents[match.end() + offset :] line_break = _get_line_break_position(right) middle = right[:line_break] + right = right[line_break:] if current_version in middle: offset += len(new_version) - len(current_version) current_version_found = True - right = right[line_break:] version_file_contents = ( left + middle.replace(current_version, new_version) + right ) diff --git a/tests/test_bump_update_version_in_files.py b/tests/test_bump_update_version_in_files.py index 0daa2ecb22..55189da030 100644 --- a/tests/test_bump_update_version_in_files.py +++ b/tests/test_bump_update_version_in_files.py @@ -1,130 +1,48 @@ -import re +from shutil import copyfile import pytest from commitizen import bump from commitizen.exceptions import CurrentVersionNotFoundError -PYPROJECT = """ -[tool.poetry] -name = "commitizen" -version = "1.2.3" -""" - -VERSION_PY = """ -__title__ = 'requests' -__description__ = 'Python HTTP for Humans.' -__url__ = 'http://python-requests.org' -__version__ = '1.2.3' -""" - -INCONSISTENT_VERSION_PY = """ -__title__ = 'requests' -__description__ = 'Python HTTP for Humans.' -__url__ = 'http://python-requests.org' -__version__ = '2.10.3' -""" - -REPEATED_VERSION_NUMBER = """ -{ - "name": "magictool", - "version": "1.2.3", - "dependencies": { - "lodash": "1.2.3" - } -} -""" - -# The order cannot be guaranteed here -CARGO_LOCK = """ -[[package]] -name = "textwrap" -version = "1.2.3" - -[[package]] -name = "there-i-fixed-it" -version = "1.2.3" - -[[package]] -name = "other-project" -version = "1.2.3" -""" - -DOCKER_COMPOSE = """ -version: "3.3" - -services: - app: - image: my-repo/my-container:v1.2.3 - command: my-command -""" - -MULTIPLE_VERSIONS_TO_UPDATE_POETRY_LOCK = """ -[[package]] -name = "to-update-1" -version = "1.2.9" - -[[package]] -name = "not-to-update" -version = "1.3.3" - -[[package]] -name = "not-to-update" -version = "1.3.3" - -[[package]] -name = "not-to-update" -version = "1.3.3" - -[[package]] -name = "not-to-update" -version = "1.3.3" - -[[package]] -name = "not-to-update" -version = "1.3.3" - -[[package]] -name = "to-update-2" -version = "1.2.9" -""" - MULTIPLE_VERSIONS_INCREASE_STRING = 'version = "1.2.9"\n' * 30 MULTIPLE_VERSIONS_REDUCE_STRING = 'version = "1.2.10"\n' * 30 +TESTING_FILE_PREFIX = "tests/testing_version_files" + @pytest.fixture(scope="function") def commitizen_config_file(tmpdir): tmp_file = tmpdir.join("pyproject.toml") - tmp_file.write(PYPROJECT) + copyfile(f"{TESTING_FILE_PREFIX}/sample_pyproject.toml", str(tmp_file)) return str(tmp_file) @pytest.fixture(scope="function") def python_version_file(tmpdir): tmp_file = tmpdir.join("__verion__.py") - tmp_file.write(VERSION_PY) + copyfile(f"{TESTING_FILE_PREFIX}/sample_version.py", str(tmp_file)) return str(tmp_file) @pytest.fixture(scope="function") def inconsistent_python_version_file(tmpdir): tmp_file = tmpdir.join("__verion__.py") - tmp_file.write(INCONSISTENT_VERSION_PY) + copyfile(f"{TESTING_FILE_PREFIX}/inconsistent_version.py", str(tmp_file)) return str(tmp_file) @pytest.fixture(scope="function") def random_location_version_file(tmpdir): tmp_file = tmpdir.join("Cargo.lock") - tmp_file.write(CARGO_LOCK) + copyfile(f"{TESTING_FILE_PREFIX}/sample_cargo.lock", str(tmp_file)) return str(tmp_file) @pytest.fixture(scope="function") def version_repeated_file(tmpdir): tmp_file = tmpdir.join("package.json") - tmp_file.write(REPEATED_VERSION_NUMBER) + copyfile(f"{TESTING_FILE_PREFIX}/repeated_version_number.json", str(tmp_file)) return str(tmp_file) @@ -145,14 +63,17 @@ def multiple_versions_reduce_string(tmpdir): @pytest.fixture(scope="function") def docker_compose_file(tmpdir): tmp_file = tmpdir.join("docker-compose.yaml") - tmp_file.write(DOCKER_COMPOSE) + copyfile(f"{TESTING_FILE_PREFIX}/sample_docker_compose.yaml", str(tmp_file)) return str(tmp_file) @pytest.fixture(scope="function") def multiple_versions_to_update_poetry_lock(tmpdir): tmp_file = tmpdir.join("pyproject.toml") - tmp_file.write(MULTIPLE_VERSIONS_TO_UPDATE_POETRY_LOCK) + copyfile( + f"{TESTING_FILE_PREFIX}/multiple_versions_to_update_pyproject.toml", + str(tmp_file), + ) return str(tmp_file) @@ -171,17 +92,19 @@ def version_files( ] -def test_update_version_in_files(version_files): +def test_update_version_in_files(version_files, file_regression): old_version = "1.2.3" new_version = "2.0.0" bump.update_version_in_files(old_version, new_version, version_files) + + file_contents = "" for filepath in version_files: with open(filepath, "r") as f: - data = f.read() - assert new_version in data + file_contents += f.read() + file_regression.check(file_contents, extension=".txt") -def test_partial_update_of_file(version_repeated_file): +def test_partial_update_of_file(version_repeated_file, file_regression): old_version = "1.2.3" new_version = "2.0.0" regex = "version" @@ -189,59 +112,53 @@ def test_partial_update_of_file(version_repeated_file): bump.update_version_in_files(old_version, new_version, [location]) with open(version_repeated_file, "r") as f: - data = f.read() - assert new_version in data - assert old_version in data + file_regression.check(f.read(), extension=".json") -def test_random_location(random_location_version_file): +def test_random_location(random_location_version_file, file_regression): old_version = "1.2.3" new_version = "2.0.0" location = f"{random_location_version_file}:there-i-fixed-it.+\nversion" bump.update_version_in_files(old_version, new_version, [location]) with open(random_location_version_file, "r") as f: - data = f.read() - assert len(re.findall(old_version, data)) == 2 - assert len(re.findall(new_version, data)) == 1 + file_regression.check(f.read(), extension=".lock") -def test_duplicates_are_change_with_no_regex(random_location_version_file): +def test_duplicates_are_change_with_no_regex( + random_location_version_file, file_regression +): old_version = "1.2.3" new_version = "2.0.0" location = f"{random_location_version_file}:version" bump.update_version_in_files(old_version, new_version, [location]) with open(random_location_version_file, "r") as f: - data = f.read() - assert len(re.findall(old_version, data)) == 0 - assert len(re.findall(new_version, data)) == 3 + file_regression.check(f.read(), extension=".lock") -def test_version_bump_increase_string_length(multiple_versions_increase_string): +def test_version_bump_increase_string_length( + multiple_versions_increase_string, file_regression +): old_version = "1.2.9" new_version = "1.2.10" - version_bump_change_string_size( - multiple_versions_increase_string, old_version, new_version - ) + location = f"{multiple_versions_increase_string}:version" + + bump.update_version_in_files(old_version, new_version, [location]) + with open(multiple_versions_increase_string, "r") as f: + file_regression.check(f.read(), extension=".txt") -def test_version_bump_reduce_string_length(multiple_versions_reduce_string): +def test_version_bump_reduce_string_length( + multiple_versions_reduce_string, file_regression +): old_version = "1.2.10" new_version = "2.0.0" - version_bump_change_string_size( - multiple_versions_reduce_string, old_version, new_version - ) - - -def version_bump_change_string_size(filename, old_version, new_version): - location = f"{filename}:version" + location = f"{multiple_versions_reduce_string}:version" bump.update_version_in_files(old_version, new_version, [location]) - with open(filename, "r") as f: - data = f.read() - assert len(re.findall(old_version, data)) == 0 - assert len(re.findall(new_version, data)) == 30 + with open(multiple_versions_reduce_string, "r") as f: + file_regression.check(f.read(), extension=".txt") def test_file_version_inconsistent_error( diff --git a/tests/test_bump_update_version_in_files/test_duplicates_are_change_with_no_regex.lock b/tests/test_bump_update_version_in_files/test_duplicates_are_change_with_no_regex.lock new file mode 100644 index 0000000000..eed8f4c79d --- /dev/null +++ b/tests/test_bump_update_version_in_files/test_duplicates_are_change_with_no_regex.lock @@ -0,0 +1,11 @@ +[[package]] +name = "textwrap" +version = "2.0.0" + +[[package]] +name = "there-i-fixed-it" +version = "2.0.0" + +[[package]] +name = "other-project" +version = "2.0.0" diff --git a/tests/test_bump_update_version_in_files/test_multiplt_versions_to_bump.toml b/tests/test_bump_update_version_in_files/test_multiplt_versions_to_bump.toml index d5e8bf082f..f279eb4d61 100644 --- a/tests/test_bump_update_version_in_files/test_multiplt_versions_to_bump.toml +++ b/tests/test_bump_update_version_in_files/test_multiplt_versions_to_bump.toml @@ -1,4 +1,3 @@ - [[package]] name = "to-update-1" version = "1.2.10" diff --git a/tests/test_bump_update_version_in_files/test_partial_update_of_file.json b/tests/test_bump_update_version_in_files/test_partial_update_of_file.json new file mode 100644 index 0000000000..59224bca04 --- /dev/null +++ b/tests/test_bump_update_version_in_files/test_partial_update_of_file.json @@ -0,0 +1,7 @@ +{ + "name": "magictool", + "version": "2.0.0", + "dependencies": { + "lodash": "1.2.3" + } +} diff --git a/tests/test_bump_update_version_in_files/test_random_location.lock b/tests/test_bump_update_version_in_files/test_random_location.lock new file mode 100644 index 0000000000..94422116aa --- /dev/null +++ b/tests/test_bump_update_version_in_files/test_random_location.lock @@ -0,0 +1,11 @@ +[[package]] +name = "textwrap" +version = "1.2.3" + +[[package]] +name = "there-i-fixed-it" +version = "2.0.0" + +[[package]] +name = "other-project" +version = "1.2.3" diff --git a/tests/test_bump_update_version_in_files/test_update_version_in_files.txt b/tests/test_bump_update_version_in_files/test_update_version_in_files.txt new file mode 100644 index 0000000000..c4e527ac47 --- /dev/null +++ b/tests/test_bump_update_version_in_files/test_update_version_in_files.txt @@ -0,0 +1,20 @@ +[tool.poetry] +name = "commitizen" +version = "2.0.0" +__title__ = "requests" +__description__ = "Python HTTP for Humans." +__url__ = "http://python-requests.org" +__version__ = "2.0.0" +{ + "name": "magictool", + "version": "2.0.0", + "dependencies": { + "lodash": "2.0.0" + } +} +version: "3.3" + +services: + app: + image: my-repo/my-container:v2.0.0 + command: my-command diff --git a/tests/test_bump_update_version_in_files/test_version_bump_increase_string_length.txt b/tests/test_bump_update_version_in_files/test_version_bump_increase_string_length.txt new file mode 100644 index 0000000000..4b6d6d64be --- /dev/null +++ b/tests/test_bump_update_version_in_files/test_version_bump_increase_string_length.txt @@ -0,0 +1,30 @@ +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" +version = "1.2.10" diff --git a/tests/test_bump_update_version_in_files/test_version_bump_reduce_string_length.txt b/tests/test_bump_update_version_in_files/test_version_bump_reduce_string_length.txt new file mode 100644 index 0000000000..8e619de1ab --- /dev/null +++ b/tests/test_bump_update_version_in_files/test_version_bump_reduce_string_length.txt @@ -0,0 +1,30 @@ +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" +version = "2.0.0" diff --git a/tests/testing_version_files/inconsistent_version.py b/tests/testing_version_files/inconsistent_version.py new file mode 100644 index 0000000000..47646762dc --- /dev/null +++ b/tests/testing_version_files/inconsistent_version.py @@ -0,0 +1,4 @@ +__title__ = "requests" +__description__ = "Python HTTP for Humans." +__url__ = "http://python-requests.org" +__version__ = "2.10.3" diff --git a/tests/testing_version_files/multiple_versions_to_update_pyproject.toml b/tests/testing_version_files/multiple_versions_to_update_pyproject.toml new file mode 100644 index 0000000000..de4ead0343 --- /dev/null +++ b/tests/testing_version_files/multiple_versions_to_update_pyproject.toml @@ -0,0 +1,27 @@ +[[package]] +name = "to-update-1" +version = "1.2.9" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "to-update-2" +version = "1.2.9" diff --git a/tests/testing_version_files/repeated_version_number.json b/tests/testing_version_files/repeated_version_number.json new file mode 100644 index 0000000000..8421026df9 --- /dev/null +++ b/tests/testing_version_files/repeated_version_number.json @@ -0,0 +1,7 @@ +{ + "name": "magictool", + "version": "1.2.3", + "dependencies": { + "lodash": "1.2.3" + } +} diff --git a/tests/testing_version_files/sample_cargo.lock b/tests/testing_version_files/sample_cargo.lock new file mode 100644 index 0000000000..a3a0b1bb7a --- /dev/null +++ b/tests/testing_version_files/sample_cargo.lock @@ -0,0 +1,11 @@ +[[package]] +name = "textwrap" +version = "1.2.3" + +[[package]] +name = "there-i-fixed-it" +version = "1.2.3" + +[[package]] +name = "other-project" +version = "1.2.3" diff --git a/tests/testing_version_files/sample_docker_compose.yaml b/tests/testing_version_files/sample_docker_compose.yaml new file mode 100644 index 0000000000..9da8caf1f6 --- /dev/null +++ b/tests/testing_version_files/sample_docker_compose.yaml @@ -0,0 +1,6 @@ +version: "3.3" + +services: + app: + image: my-repo/my-container:v1.2.3 + command: my-command diff --git a/tests/testing_version_files/sample_pyproject.toml b/tests/testing_version_files/sample_pyproject.toml new file mode 100644 index 0000000000..9f50155cb7 --- /dev/null +++ b/tests/testing_version_files/sample_pyproject.toml @@ -0,0 +1,3 @@ +[tool.poetry] +name = "commitizen" +version = "1.2.3" diff --git a/tests/testing_version_files/sample_version.py b/tests/testing_version_files/sample_version.py new file mode 100644 index 0000000000..4dd4512dba --- /dev/null +++ b/tests/testing_version_files/sample_version.py @@ -0,0 +1,4 @@ +__title__ = "requests" +__description__ = "Python HTTP for Humans." +__url__ = "http://python-requests.org" +__version__ = "1.2.3" From fde3b72096d6d53e45c65723ac752015029948b9 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Wed, 26 May 2021 17:24:50 +0800 Subject: [PATCH 368/427] test(bump): add test case that fails when using regex with version file without end of line if we bump with version file with no end of line through regex, the last version will be ignored --- .pre-commit-config.yaml | 2 +- .../inconsistent_version.py | 0 ...multiple_versions_to_update_pyproject.toml | 0 ...e_versions_to_update_pyproject_wo_eol.toml | 27 +++++++++++++++++++ .../repeated_version_number.json | 0 .../sample_cargo.lock | 0 .../sample_docker_compose.yaml | 0 .../sample_pyproject.toml | 0 .../sample_version.py | 0 tests/test_bump_update_version_in_files.py | 18 ++++++++----- ..._multiplt_versions_to_bump_with_eol_.toml} | 0 ...ultiplt_versions_to_bump_without_eol_.toml | 27 +++++++++++++++++++ 12 files changed, 67 insertions(+), 7 deletions(-) rename tests/{testing_version_files => data}/inconsistent_version.py (100%) rename tests/{testing_version_files => data}/multiple_versions_to_update_pyproject.toml (100%) create mode 100644 tests/data/multiple_versions_to_update_pyproject_wo_eol.toml rename tests/{testing_version_files => data}/repeated_version_number.json (100%) rename tests/{testing_version_files => data}/sample_cargo.lock (100%) rename tests/{testing_version_files => data}/sample_docker_compose.yaml (100%) rename tests/{testing_version_files => data}/sample_pyproject.toml (100%) rename tests/{testing_version_files => data}/sample_version.py (100%) rename tests/test_bump_update_version_in_files/{test_multiplt_versions_to_bump.toml => test_multiplt_versions_to_bump_with_eol_.toml} (100%) create mode 100644 tests/test_bump_update_version_in_files/test_multiplt_versions_to_bump_without_eol_.toml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6ecfdc2041..a5c2d68036 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ repos: hooks: - id: check-vcs-permalinks - id: end-of-file-fixer - exclude: "tests/test_*/*" + exclude: "tests/[test_*|data]/*" - id: trailing-whitespace args: [--markdown-linebreak-ext=md] - id: debug-statements diff --git a/tests/testing_version_files/inconsistent_version.py b/tests/data/inconsistent_version.py similarity index 100% rename from tests/testing_version_files/inconsistent_version.py rename to tests/data/inconsistent_version.py diff --git a/tests/testing_version_files/multiple_versions_to_update_pyproject.toml b/tests/data/multiple_versions_to_update_pyproject.toml similarity index 100% rename from tests/testing_version_files/multiple_versions_to_update_pyproject.toml rename to tests/data/multiple_versions_to_update_pyproject.toml diff --git a/tests/data/multiple_versions_to_update_pyproject_wo_eol.toml b/tests/data/multiple_versions_to_update_pyproject_wo_eol.toml new file mode 100644 index 0000000000..e2746fa9eb --- /dev/null +++ b/tests/data/multiple_versions_to_update_pyproject_wo_eol.toml @@ -0,0 +1,27 @@ +[[package]] +name = "to-update-1" +version = "1.2.9" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "to-update-2" +version = "1.2.9" \ No newline at end of file diff --git a/tests/testing_version_files/repeated_version_number.json b/tests/data/repeated_version_number.json similarity index 100% rename from tests/testing_version_files/repeated_version_number.json rename to tests/data/repeated_version_number.json diff --git a/tests/testing_version_files/sample_cargo.lock b/tests/data/sample_cargo.lock similarity index 100% rename from tests/testing_version_files/sample_cargo.lock rename to tests/data/sample_cargo.lock diff --git a/tests/testing_version_files/sample_docker_compose.yaml b/tests/data/sample_docker_compose.yaml similarity index 100% rename from tests/testing_version_files/sample_docker_compose.yaml rename to tests/data/sample_docker_compose.yaml diff --git a/tests/testing_version_files/sample_pyproject.toml b/tests/data/sample_pyproject.toml similarity index 100% rename from tests/testing_version_files/sample_pyproject.toml rename to tests/data/sample_pyproject.toml diff --git a/tests/testing_version_files/sample_version.py b/tests/data/sample_version.py similarity index 100% rename from tests/testing_version_files/sample_version.py rename to tests/data/sample_version.py diff --git a/tests/test_bump_update_version_in_files.py b/tests/test_bump_update_version_in_files.py index 55189da030..ad1beee774 100644 --- a/tests/test_bump_update_version_in_files.py +++ b/tests/test_bump_update_version_in_files.py @@ -8,7 +8,7 @@ MULTIPLE_VERSIONS_INCREASE_STRING = 'version = "1.2.9"\n' * 30 MULTIPLE_VERSIONS_REDUCE_STRING = 'version = "1.2.10"\n' * 30 -TESTING_FILE_PREFIX = "tests/testing_version_files" +TESTING_FILE_PREFIX = "tests/data" @pytest.fixture(scope="function") @@ -19,7 +19,7 @@ def commitizen_config_file(tmpdir): @pytest.fixture(scope="function") -def python_version_file(tmpdir): +def python_version_file(tmpdir, request): tmp_file = tmpdir.join("__verion__.py") copyfile(f"{TESTING_FILE_PREFIX}/sample_version.py", str(tmp_file)) return str(tmp_file) @@ -67,12 +67,18 @@ def docker_compose_file(tmpdir): return str(tmp_file) -@pytest.fixture(scope="function") -def multiple_versions_to_update_poetry_lock(tmpdir): +@pytest.fixture( + scope="function", + params=( + "multiple_versions_to_update_pyproject.toml", + "multiple_versions_to_update_pyproject_wo_eol.toml", + ), + ids=("with_eol", "without_eol"), +) +def multiple_versions_to_update_poetry_lock(tmpdir, request): tmp_file = tmpdir.join("pyproject.toml") copyfile( - f"{TESTING_FILE_PREFIX}/multiple_versions_to_update_pyproject.toml", - str(tmp_file), + f"{TESTING_FILE_PREFIX}/{request.param}", str(tmp_file), ) return str(tmp_file) diff --git a/tests/test_bump_update_version_in_files/test_multiplt_versions_to_bump.toml b/tests/test_bump_update_version_in_files/test_multiplt_versions_to_bump_with_eol_.toml similarity index 100% rename from tests/test_bump_update_version_in_files/test_multiplt_versions_to_bump.toml rename to tests/test_bump_update_version_in_files/test_multiplt_versions_to_bump_with_eol_.toml diff --git a/tests/test_bump_update_version_in_files/test_multiplt_versions_to_bump_without_eol_.toml b/tests/test_bump_update_version_in_files/test_multiplt_versions_to_bump_without_eol_.toml new file mode 100644 index 0000000000..47092b958b --- /dev/null +++ b/tests/test_bump_update_version_in_files/test_multiplt_versions_to_bump_without_eol_.toml @@ -0,0 +1,27 @@ +[[package]] +name = "to-update-1" +version = "1.2.10" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "not-to-update" +version = "1.3.3" + +[[package]] +name = "to-update-2" +version = "1.2.10" \ No newline at end of file From 76b3030f65ac310a2def731a558763f363cc8af3 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Wed, 26 May 2021 17:42:36 +0800 Subject: [PATCH 369/427] fix(bump): fix error due to bumping version file without eol through regex --- commitizen/bump.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index c4fbadc07c..9312491044 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -186,9 +186,11 @@ def _bump_with_regex(version_file_contents, current_version, new_version, regex) for match in re.finditer(regex, version_file_contents, re.MULTILINE): left = version_file_contents[: match.end() + offset] right = version_file_contents[match.end() + offset :] - line_break = _get_line_break_position(right) + + line_break = right.find("\n") middle = right[:line_break] right = right[line_break:] + if current_version in middle: offset += len(new_version) - len(current_version) current_version_found = True @@ -198,11 +200,6 @@ def _bump_with_regex(version_file_contents, current_version, new_version, regex) return current_version_found, version_file_contents -def _get_line_break_position(text: str) -> int: - position = text.find("\n") - return max(position, 0) - - def _version_to_regex(version: str): clean_regex = version.replace(".", r"\.").replace("+", r"\+") return re.compile(f"{clean_regex}") From b36594db12d8555a36f83fd42e1c9ea351dfff14 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Wed, 26 May 2021 17:58:57 +0800 Subject: [PATCH 370/427] test(bump): refactor file loading with extracted utility function --- tests/test_bump_update_version_in_files.py | 77 +++++++++++----------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/tests/test_bump_update_version_in_files.py b/tests/test_bump_update_version_in_files.py index ad1beee774..a00286df71 100644 --- a/tests/test_bump_update_version_in_files.py +++ b/tests/test_bump_update_version_in_files.py @@ -1,6 +1,7 @@ from shutil import copyfile import pytest +from py._path.local import LocalPath from commitizen import bump from commitizen.exceptions import CurrentVersionNotFoundError @@ -11,60 +12,50 @@ TESTING_FILE_PREFIX = "tests/data" +def _copy_sample_file_to_tmpdir( + tmpdir: LocalPath, source_filename: str, dest_filename: str +) -> str: + tmp_file = tmpdir.join(dest_filename) + copyfile(f"{TESTING_FILE_PREFIX}/{source_filename}", str(tmp_file)) + return str(tmp_file) + + @pytest.fixture(scope="function") def commitizen_config_file(tmpdir): - tmp_file = tmpdir.join("pyproject.toml") - copyfile(f"{TESTING_FILE_PREFIX}/sample_pyproject.toml", str(tmp_file)) - return str(tmp_file) + return _copy_sample_file_to_tmpdir( + tmpdir, "sample_pyproject.toml", "pyproject.toml" + ) @pytest.fixture(scope="function") def python_version_file(tmpdir, request): - tmp_file = tmpdir.join("__verion__.py") - copyfile(f"{TESTING_FILE_PREFIX}/sample_version.py", str(tmp_file)) - return str(tmp_file) + return _copy_sample_file_to_tmpdir(tmpdir, "sample_version.py", "__version__.py") @pytest.fixture(scope="function") def inconsistent_python_version_file(tmpdir): - tmp_file = tmpdir.join("__verion__.py") - copyfile(f"{TESTING_FILE_PREFIX}/inconsistent_version.py", str(tmp_file)) - return str(tmp_file) + return _copy_sample_file_to_tmpdir( + tmpdir, "inconsistent_version.py", "__version__.py" + ) @pytest.fixture(scope="function") def random_location_version_file(tmpdir): - tmp_file = tmpdir.join("Cargo.lock") - copyfile(f"{TESTING_FILE_PREFIX}/sample_cargo.lock", str(tmp_file)) - return str(tmp_file) + return _copy_sample_file_to_tmpdir(tmpdir, "sample_cargo.lock", "Cargo.lock") @pytest.fixture(scope="function") def version_repeated_file(tmpdir): - tmp_file = tmpdir.join("package.json") - copyfile(f"{TESTING_FILE_PREFIX}/repeated_version_number.json", str(tmp_file)) - return str(tmp_file) - - -@pytest.fixture(scope="function") -def multiple_versions_increase_string(tmpdir): - tmp_file = tmpdir.join("anyfile") - tmp_file.write(MULTIPLE_VERSIONS_INCREASE_STRING) - return str(tmp_file) - - -@pytest.fixture(scope="function") -def multiple_versions_reduce_string(tmpdir): - tmp_file = tmpdir.join("anyfile") - tmp_file.write(MULTIPLE_VERSIONS_REDUCE_STRING) - return str(tmp_file) + return _copy_sample_file_to_tmpdir( + tmpdir, "repeated_version_number.json", "package.json" + ) @pytest.fixture(scope="function") def docker_compose_file(tmpdir): - tmp_file = tmpdir.join("docker-compose.yaml") - copyfile(f"{TESTING_FILE_PREFIX}/sample_docker_compose.yaml", str(tmp_file)) - return str(tmp_file) + return _copy_sample_file_to_tmpdir( + tmpdir, "sample_docker_compose.yaml", "docker-compose.yaml" + ) @pytest.fixture( @@ -76,10 +67,20 @@ def docker_compose_file(tmpdir): ids=("with_eol", "without_eol"), ) def multiple_versions_to_update_poetry_lock(tmpdir, request): - tmp_file = tmpdir.join("pyproject.toml") - copyfile( - f"{TESTING_FILE_PREFIX}/{request.param}", str(tmp_file), - ) + return _copy_sample_file_to_tmpdir(tmpdir, request.param, "pyproject.toml") + + +@pytest.fixture(scope="function") +def multiple_versions_increase_string(tmpdir): + tmp_file = tmpdir.join("anyfile") + tmp_file.write(MULTIPLE_VERSIONS_INCREASE_STRING) + return str(tmp_file) + + +@pytest.fixture(scope="function") +def multiple_versions_reduce_string(tmpdir): + tmp_file = tmpdir.join("anyfile") + tmp_file.write(MULTIPLE_VERSIONS_REDUCE_STRING) return str(tmp_file) @@ -90,12 +91,12 @@ def version_files( version_repeated_file, docker_compose_file, ): - return [ + return ( commitizen_config_file, python_version_file, version_repeated_file, docker_compose_file, - ] + ) def test_update_version_in_files(version_files, file_regression): From 96078744448023dc01d4816085d63291fb7760a0 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Wed, 26 May 2021 18:14:41 +0800 Subject: [PATCH 371/427] test(git): add test case for is_staging_clean --- tests/test_git.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test_git.py b/tests/test_git.py index 8ba2f64cb8..1fe2b9251a 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -152,3 +152,14 @@ def test_get_latest_tag_name(tmp_commitizen_project): cmd.run("git tag 1.0") tag_name = git.get_latest_tag_name() assert tag_name == "1.0" + + +def test_is_staging_clean(tmp_commitizen_project): + with tmp_commitizen_project.as_cwd(): + assert git.is_staging_clean() is True + + cmd.run("touch test_file") + cmd.run("git add test_file") + cmd.run("echo 'test' > test_file") + + assert git.is_staging_clean() is False From 6192fc389a224db8ded0a52ba4004d479ec752ae Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 26 May 2021 14:12:25 +0000 Subject: [PATCH 372/427] =?UTF-8?q?bump:=20version=202.17.6=20=E2=86=92=20?= =?UTF-8?q?2.17.7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 7 +++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 167c010b7a..6d1f74f2ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,11 @@ +## v2.17.7 (2021-05-26) + +### Fix + +- **bump**: fix error due to bumping version file without eol through regex +- **bump**: fix offset error due to partially match + ## v2.17.6 (2021-05-06) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index a4d4630238..36ce2b9412 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.17.6" +__version__ = "2.17.7" diff --git a/pyproject.toml b/pyproject.toml index b344305706..dadbd30d86 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.17.6" +version = "2.17.7" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.17.6" +version = "2.17.7" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 72d9dbd7124dff8e6874c85cb8a2d7e9a263dab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fraire=20Willemo=C3=ABs=2C=20Santiago?= <santiwilly@gmail.com> Date: Fri, 28 May 2021 10:40:26 +0200 Subject: [PATCH 373/427] fix(changelog): annotated tags not generating proper changelog --- commitizen/git.py | 21 ++++++++++-- tests/commands/test_changelog_command.py | 27 ++++++++++++++++ ...p_a_changelog_sample_with_annotated_tag.md | 32 +++++++++++++++++++ tests/test_git.py | 6 ++-- 4 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 tests/commands/test_changelog_command/test_changelog_incremental_keep_a_changelog_sample_with_annotated_tag.md diff --git a/commitizen/git.py b/commitizen/git.py index b8fbd0715a..a4476de6bb 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -44,6 +44,15 @@ def __init__(self, name, rev, date): def __repr__(self): return f"GitTag('{self.name}', '{self.rev}', '{self.date}')" + @classmethod + def from_line(cls, line: str, inner_delimiter: str) -> "GitTag": + + name, objectname, date, obj = line.split(inner_delimiter) + if not obj: + obj = objectname + + return cls(name=name, rev=obj, date=date) + def tag(tag: str, annotated: bool = False): c = cmd.run(f"git tag -a {tag} -m {tag}" if annotated else f"git tag {tag}") @@ -100,13 +109,19 @@ def get_tags(dateformat: str = "%Y-%m-%d") -> List[GitTag]: formatter = ( f'"%(refname:lstrip=2){inner_delimiter}' f"%(objectname){inner_delimiter}" - f'%(committerdate:format:{dateformat})"' + f"%(creatordate:format:{dateformat}){inner_delimiter}" + f'%(object)"' ) - c = cmd.run(f"git tag --format={formatter} --sort=-committerdate") + c = cmd.run(f"git tag --format={formatter} --sort=-creatordate") + if c.err or not c.out: return [] - git_tags = [GitTag(*line.split(inner_delimiter)) for line in c.out.split("\n")[:-1]] + git_tags = [ + GitTag.from_line(line=line, inner_delimiter=inner_delimiter) + for line in c.out.split("\n")[:-1] + ] + return git_tags diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index 7448fee320..95e4775aad 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -453,3 +453,30 @@ def test_changelog_config_start_rev_option(mocker, capsys, config_path): out, _ = capsys.readouterr() assert out == "## Unreleased\n\n### Feat\n\n- after 0.2\n- after 0.2.0\n\n" + + +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_changelog_incremental_keep_a_changelog_sample_with_annotated_tag( + mocker, capsys, changelog_path, file_regression +): + """Fix #378""" + with open(changelog_path, "w") as f: + f.write(KEEP_A_CHANGELOG) + create_file_and_commit("irrelevant commit") + git.tag("1.0.0", annotated=True) + + create_file_and_commit("feat: add new output") + create_file_and_commit("fix: output glitch") + create_file_and_commit("fix: mama gotta work") + create_file_and_commit("feat: add more stuff") + create_file_and_commit("Merge into master") + + testargs = ["cz", "changelog", "--incremental"] + + mocker.patch.object(sys, "argv", testargs) + cli.main() + + with open(changelog_path, "r") as f: + out = f.read() + + file_regression.check(out, extension=".md") diff --git a/tests/commands/test_changelog_command/test_changelog_incremental_keep_a_changelog_sample_with_annotated_tag.md b/tests/commands/test_changelog_command/test_changelog_incremental_keep_a_changelog_sample_with_annotated_tag.md new file mode 100644 index 0000000000..56e2cf81f5 --- /dev/null +++ b/tests/commands/test_changelog_command/test_changelog_incremental_keep_a_changelog_sample_with_annotated_tag.md @@ -0,0 +1,32 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +### Feat + +- add more stuff +- add new output + +### Fix + +- mama gotta work +- output glitch + +## [1.0.0] - 2017-06-20 +### Added +- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8). +- Version navigation. + +### Changed +- Start using "changelog" over "change log" since it's the common usage. + +### Removed +- Section about "changelog" vs "CHANGELOG". + +## [0.3.0] - 2015-12-03 +### Added +- RU translation from [@aishek](https://github.com/aishek). diff --git a/tests/test_git.py b/tests/test_git.py index 1fe2b9251a..03ddcbaa13 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -19,9 +19,9 @@ def test_git_object_eq(): def test_get_tags(mocker): tag_str = ( - "v1.0.0---inner_delimiter---333---inner_delimiter---2020-01-20\n" - "v0.5.0---inner_delimiter---222---inner_delimiter---2020-01-17\n" - "v0.0.1---inner_delimiter---111---inner_delimiter---2020-01-17\n" + "v1.0.0---inner_delimiter---333---inner_delimiter---2020-01-20---inner_delimiter---\n" + "v0.5.0---inner_delimiter---222---inner_delimiter---2020-01-17---inner_delimiter---\n" + "v0.0.1---inner_delimiter---111---inner_delimiter---2020-01-17---inner_delimiter---\n" ) mocker.patch("commitizen.cmd.run", return_value=FakeCommand(out=tag_str)) From 8829441fcf0dffb72e1f65447812f068f8564819 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Fri, 28 May 2021 08:54:52 +0000 Subject: [PATCH 374/427] =?UTF-8?q?bump:=20version=202.17.7=20=E2=86=92=20?= =?UTF-8?q?2.17.8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d1f74f2ff..d4c53f528c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +## v2.17.8 (2021-05-28) + +### Fix + +- **changelog**: annotated tags not generating proper changelog + ## v2.17.7 (2021-05-26) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 36ce2b9412..757a1dcbe0 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.17.7" +__version__ = "2.17.8" diff --git a/pyproject.toml b/pyproject.toml index dadbd30d86..a13c53a733 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.17.7" +version = "2.17.8" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.17.7" +version = "2.17.8" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 96265ce7ebe6fc6bd97b113d90ff3b10566392db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fraire=20Willemo=C3=ABs=2C=20Santiago?= <santiwilly@gmail.com> Date: Fri, 28 May 2021 11:14:15 +0200 Subject: [PATCH 375/427] ci(homebrewpublish): add tag to homebrew formula action --- .github/workflows/homebrewpublish.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/homebrewpublish.yaml b/.github/workflows/homebrewpublish.yaml index 267ba4ec33..817d881794 100644 --- a/.github/workflows/homebrewpublish.yaml +++ b/.github/workflows/homebrewpublish.yaml @@ -13,8 +13,19 @@ jobs: steps: - name: Checkout uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v1 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install -U commitizen + - name: Set Project version env variable + run: | + echo "project_version=$(cz version --project)" >> $GITHUB_ENV - name: Update Homebrew formula uses: dawidd6/action-homebrew-bump-formula@v3 with: token: ${{secrets.PERSONAL_ACCESS_TOKEN}} formula: commitizen + tag: v${{ env.project_version }} From 7eec5a023b81f67dcb978babfe689cec7b2474eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fraire=20Willemo=C3=ABs=2C=20Santiago?= <santiwilly@gmail.com> Date: Fri, 11 Jun 2021 12:18:27 +0200 Subject: [PATCH 376/427] fix(changelog): generating changelog after a pre-release Closes #357 --- commitizen/defaults.py | 2 +- tests/commands/test_changelog_command.py | 33 +++++++++++++++ ...l_with_release_candidate_version_alpha_.md | 40 +++++++++++++++++++ ...al_with_release_candidate_version_beta_.md | 40 +++++++++++++++++++ ...ntal_with_release_candidate_version_rc_.md | 40 +++++++++++++++++++ 5 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 tests/commands/test_changelog_command/test_changelog_incremental_with_release_candidate_version_alpha_.md create mode 100644 tests/commands/test_changelog_command/test_changelog_incremental_with_release_candidate_version_beta_.md create mode 100644 tests/commands/test_changelog_command/test_changelog_incremental_with_release_candidate_version_rc_.md diff --git a/commitizen/defaults.py b/commitizen/defaults.py index 77fc4b0a50..83f2ca4636 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -43,4 +43,4 @@ change_type_order = ["BREAKING CHANGE", "feat", "fix", "refactor", "perf"] commit_parser = r"^(?P<change_type>feat|fix|refactor|perf|BREAKING CHANGE)(?:\((?P<scope>[^()\r\n]*)\)|\()?(?P<breaking>!)?:\s(?P<message>.*)?" # noqa -version_parser = r"(?P<version>([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+)?)" +version_parser = r"(?P<version>([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+)?(\w+)?)" diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index 95e4775aad..34ef90a302 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -480,3 +480,36 @@ def test_changelog_incremental_keep_a_changelog_sample_with_annotated_tag( out = f.read() file_regression.check(out, extension=".md") + + +@pytest.mark.parametrize("test_input", ["rc", "alpha", "beta"]) +@pytest.mark.usefixtures("tmp_commitizen_project") +def test_changelog_incremental_with_release_candidate_version( + mocker, capsys, changelog_path, file_regression, test_input +): + """Fix #357""" + with open(changelog_path, "w") as f: + f.write(KEEP_A_CHANGELOG) + create_file_and_commit("irrelevant commit") + git.tag("1.0.0", annotated=True) + + create_file_and_commit("feat: add new output") + create_file_and_commit("fix: output glitch") + + testargs = ["cz", "bump", "--changelog", "--prerelease", test_input, "--yes"] + mocker.patch.object(sys, "argv", testargs) + cli.main() + + create_file_and_commit("fix: mama gotta work") + create_file_and_commit("feat: add more stuff") + create_file_and_commit("Merge into master") + + testargs = ["cz", "changelog", "--incremental"] + + mocker.patch.object(sys, "argv", testargs) + cli.main() + + with open(changelog_path, "r") as f: + out = f.read() + + file_regression.check(out, extension=".md") diff --git a/tests/commands/test_changelog_command/test_changelog_incremental_with_release_candidate_version_alpha_.md b/tests/commands/test_changelog_command/test_changelog_incremental_with_release_candidate_version_alpha_.md new file mode 100644 index 0000000000..1fd5ca870d --- /dev/null +++ b/tests/commands/test_changelog_command/test_changelog_incremental_with_release_candidate_version_alpha_.md @@ -0,0 +1,40 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +### Feat + +- add more stuff + +### Fix + +- mama gotta work + +## 0.2.0a0 (2021-06-11) + +### Fix + +- output glitch + +### Feat + +- add new output + +## [1.0.0] - 2017-06-20 +### Added +- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8). +- Version navigation. + +### Changed +- Start using "changelog" over "change log" since it's the common usage. + +### Removed +- Section about "changelog" vs "CHANGELOG". + +## [0.3.0] - 2015-12-03 +### Added +- RU translation from [@aishek](https://github.com/aishek). diff --git a/tests/commands/test_changelog_command/test_changelog_incremental_with_release_candidate_version_beta_.md b/tests/commands/test_changelog_command/test_changelog_incremental_with_release_candidate_version_beta_.md new file mode 100644 index 0000000000..6ef1c0daad --- /dev/null +++ b/tests/commands/test_changelog_command/test_changelog_incremental_with_release_candidate_version_beta_.md @@ -0,0 +1,40 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +### Feat + +- add more stuff + +### Fix + +- mama gotta work + +## 0.2.0b0 (2021-06-11) + +### Fix + +- output glitch + +### Feat + +- add new output + +## [1.0.0] - 2017-06-20 +### Added +- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8). +- Version navigation. + +### Changed +- Start using "changelog" over "change log" since it's the common usage. + +### Removed +- Section about "changelog" vs "CHANGELOG". + +## [0.3.0] - 2015-12-03 +### Added +- RU translation from [@aishek](https://github.com/aishek). diff --git a/tests/commands/test_changelog_command/test_changelog_incremental_with_release_candidate_version_rc_.md b/tests/commands/test_changelog_command/test_changelog_incremental_with_release_candidate_version_rc_.md new file mode 100644 index 0000000000..1898179dbf --- /dev/null +++ b/tests/commands/test_changelog_command/test_changelog_incremental_with_release_candidate_version_rc_.md @@ -0,0 +1,40 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +### Feat + +- add more stuff + +### Fix + +- mama gotta work + +## 0.2.0rc0 (2021-06-11) + +### Fix + +- output glitch + +### Feat + +- add new output + +## [1.0.0] - 2017-06-20 +### Added +- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8). +- Version navigation. + +### Changed +- Start using "changelog" over "change log" since it's the common usage. + +### Removed +- Section about "changelog" vs "CHANGELOG". + +## [0.3.0] - 2015-12-03 +### Added +- RU translation from [@aishek](https://github.com/aishek). From d82727c1931eee1d5929880c8d8731a5bbaba17a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fraire=20Willemo=C3=ABs=2C=20Santiago?= <santiwilly@gmail.com> Date: Fri, 11 Jun 2021 12:33:27 +0200 Subject: [PATCH 377/427] docs(README): add pre-commit badge --- docs/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/README.md b/docs/README.md index f930841380..ea45b2d68a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,6 +5,7 @@ [![Supported versions](https://img.shields.io/pypi/pyversions/commitizen.svg?style=flat-square)](https://pypi.org/project/commitizen/) [![homebrew](https://img.shields.io/homebrew/v/commitizen?color=teal&style=flat-square)](https://formulae.brew.sh/formula/commitizen) [![Codecov](https://img.shields.io/codecov/c/github/commitizen-tools/commitizen.svg?style=flat-square)](https://codecov.io/gh/commitizen-tools/commitizen) +[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?style=flat-square&logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) ![Using commitizen cli](images/demo.gif) From 7573d167b015f6104c5fbb8cfcf285bbeb8f928b Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Fri, 11 Jun 2021 17:13:15 +0000 Subject: [PATCH 378/427] =?UTF-8?q?bump:=20version=202.17.8=20=E2=86=92=20?= =?UTF-8?q?2.17.9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4c53f528c..198f5a71e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +## v2.17.9 (2021-06-11) + +### Fix + +- **changelog**: generating changelog after a pre-release + ## v2.17.8 (2021-05-28) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 757a1dcbe0..1ad4769cce 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.17.8" +__version__ = "2.17.9" diff --git a/pyproject.toml b/pyproject.toml index a13c53a733..7f7e6d3720 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.17.8" +version = "2.17.9" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.17.8" +version = "2.17.9" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 00f81d3bc4fc53982898af7bac9e176b648cce18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fraire=20Willemo=C3=ABs=2C=20Santiago?= <santiwilly@gmail.com> Date: Mon, 21 Jun 2021 19:15:06 +0200 Subject: [PATCH 379/427] fix: add support for jinja2 v3 Closes #391 --- pyproject.toml | 3 ++- tests/commands/test_changelog_command.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7f7e6d3720..fdfa833ee2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,7 +51,7 @@ colorama = "^0.4.1" termcolor = "^1.1" packaging = ">=19,<21" tomlkit = ">=0.5.3,<1.0.0" -jinja2 = "^2.10.3" +jinja2 = ">=2.10.3" pyyaml = ">=3.08" argcomplete = "^1.12.1" @@ -71,6 +71,7 @@ freezegun = "^0.3.15" pydocstyle = "^5.0.2" pre-commit = "^2.6.0" pytest-regressions = "^2.2.0" +pytest-freezegun = "^0.4.2" [tool.poetry.scripts] cz = "commitizen.cli:main" diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index 34ef90a302..02e0e74644 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -484,6 +484,7 @@ def test_changelog_incremental_keep_a_changelog_sample_with_annotated_tag( @pytest.mark.parametrize("test_input", ["rc", "alpha", "beta"]) @pytest.mark.usefixtures("tmp_commitizen_project") +@pytest.mark.freeze_time("2021-06-11") def test_changelog_incremental_with_release_candidate_version( mocker, capsys, changelog_path, file_regression, test_input ): From dc22f2e940959b4bdf116d1c6d6cb16b1bdae81c Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Tue, 22 Jun 2021 07:16:23 +0000 Subject: [PATCH 380/427] =?UTF-8?q?bump:=20version=202.17.9=20=E2=86=92=20?= =?UTF-8?q?2.17.10?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 198f5a71e8..09148fface 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +## v2.17.10 (2021-06-22) + +### Fix + +- add support for jinja2 v3 + ## v2.17.9 (2021-06-11) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 1ad4769cce..81fde34689 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.17.9" +__version__ = "2.17.10" diff --git a/pyproject.toml b/pyproject.toml index fdfa833ee2..9d39fcfadb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.17.9" +version = "2.17.10" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.17.9" +version = "2.17.10" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 986f2d8fda44bd69e1d1763ab3a3cadf120566df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fraire=20Willemo=C3=ABs=2C=20Santiago?= <santiwilly@gmail.com> Date: Wed, 23 Jun 2021 20:57:34 +0200 Subject: [PATCH 381/427] fix: correct indentation for json config for better readability --- commitizen/config/json_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commitizen/config/json_config.py b/commitizen/config/json_config.py index 725e37a0eb..445f2aac5f 100644 --- a/commitizen/config/json_config.py +++ b/commitizen/config/json_config.py @@ -27,7 +27,7 @@ def set_key(self, key, value): parser["commitizen"][key] = value with open(self.path, "w") as f: - json.dump(parser, f) + json.dump(parser, f, indent=2) return self def _parse_setting(self, data: Union[bytes, str]): From bec20ebf433f2281c70f1eb4b0b6a1d0ed83e9b2 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Thu, 24 Jun 2021 08:50:45 +0000 Subject: [PATCH 382/427] =?UTF-8?q?bump:=20version=202.17.10=20=E2=86=92?= =?UTF-8?q?=202.17.11?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09148fface..3f6d6b193e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +## v2.17.11 (2021-06-24) + +### Fix + +- correct indentation for json config for better readability + ## v2.17.10 (2021-06-22) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 81fde34689..37684dd0a9 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.17.10" +__version__ = "2.17.11" diff --git a/pyproject.toml b/pyproject.toml index 9d39fcfadb..2e7f806d4d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.17.10" +version = "2.17.11" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.17.10" +version = "2.17.11" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 9eae518235d051f145807ddf971ceb79ad49953a Mon Sep 17 00:00:00 2001 From: Jeffrey James <lobotmcj@gmail.com> Date: Mon, 5 Jul 2021 23:20:12 -0400 Subject: [PATCH 383/427] fix(git.py): ensure signed commits in changelog when git config log.showsignature=true #397 --- commitizen/git.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/commitizen/git.py b/commitizen/git.py index a4476de6bb..2904d6cb05 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -77,7 +77,9 @@ def get_commits( args: str = "", ) -> List[GitCommit]: """Get the commits between start and end.""" - git_log_cmd = f"git log --pretty={log_format}{delimiter} {args}" + git_log_cmd = ( + f"git -c log.showSignature=False log --pretty={log_format}{delimiter} {args}" + ) if start: c = cmd.run(f"{git_log_cmd} {start}..{end}") From 184c439603d6060892076057a2a2a52d7b73de76 Mon Sep 17 00:00:00 2001 From: Jeffrey James <lobotmcj@gmail.com> Date: Tue, 6 Jul 2021 01:47:41 -0400 Subject: [PATCH 384/427] test(git.py): Test get_commits() with a gpg-signed commit #397 --- tests/test_git.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/test_git.py b/tests/test_git.py index 03ddcbaa13..dc8023b956 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -1,4 +1,5 @@ import inspect +import shutil from typing import List, Optional import pytest @@ -137,6 +138,27 @@ def test_get_commits_without_breakline_in_each_commit(mocker): ) +def test_get_commits_with_signature(): + config_file = ".git/config" + config_backup = ".git/config.bak" + shutil.copy(config_file, config_backup) + + try: + # temporarily turn on --show-signature + cmd.run("git config log.showsignature true") + + # retrieve a commit that we know has a signature + commit = git.get_commits( + start="bec20ebf433f2281c70f1eb4b0b6a1d0ed83e9b2", + end="9eae518235d051f145807ddf971ceb79ad49953a", + )[0] + + assert commit.title.startswith("fix") + finally: + # restore the repo's original config + shutil.move(config_backup, config_file) + + def test_get_tag_names_has_correct_arrow_annotation(): arrow_annotation = inspect.getfullargspec(git.get_tag_names).annotations["return"] From 4dad5c87491d1503307f803a7bd6c6060841108f Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Tue, 6 Jul 2021 17:44:16 +0000 Subject: [PATCH 385/427] =?UTF-8?q?bump:=20version=202.17.11=20=E2=86=92?= =?UTF-8?q?=202.17.12?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f6d6b193e..ddfa7f2cfa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +## v2.17.12 (2021-07-06) + +### Fix + +- **git.py**: ensure signed commits in changelog when git config log.showsignature=true + ## v2.17.11 (2021-06-24) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 37684dd0a9..2943092d1b 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.17.11" +__version__ = "2.17.12" diff --git a/pyproject.toml b/pyproject.toml index 2e7f806d4d..a3dcdfe264 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.17.11" +version = "2.17.12" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.17.11" +version = "2.17.12" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 99648b5c39a08703eb9ca10b3484e3741a77fd43 Mon Sep 17 00:00:00 2001 From: Wojciech Kusa <WojciechKusa@users.noreply.github.com> Date: Tue, 13 Jul 2021 17:18:00 +0200 Subject: [PATCH 386/427] docs(README): fix URL in README.md fix link to Customization --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index ea45b2d68a..fa62b2eab6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -178,7 +178,7 @@ See [Third-Party Commitizen Templates](third-party-commitizen.md). ### Why are `revert` and `chore` valid types in the check pattern of cz conventional_commits but not types we can select? `revert` and `chore` are added to the "pattern" in `cz check` in order to prevent backward errors, but officially they are not part of conventional commits, we are using the latest [types from Angular](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#type) (they used to but were removed). -However, you can create a customized `cz` with those extra types. (See [Customization](https://commitizen-tools.github.io/commitizen/customization/)) +However, you can create a customized `cz` with those extra types. (See [Customization](https://commitizen-tools.github.io/commitizen/customization.html)) See more discussion in issue [#142](https://github.com/commitizen-tools/commitizen/issues/142) and [#36](https://github.com/commitizen-tools/commitizen/issues/36) From 7a347788b87ac6cbfff55dd556f5bd84e1ac6944 Mon Sep 17 00:00:00 2001 From: Wojciech Kusa <WojciechKusa@users.noreply.github.com> Date: Wed, 14 Jul 2021 15:17:34 +0200 Subject: [PATCH 387/427] docs(README): fix URL in README.md --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index fa62b2eab6..f8482f4a69 100644 --- a/docs/README.md +++ b/docs/README.md @@ -178,7 +178,7 @@ See [Third-Party Commitizen Templates](third-party-commitizen.md). ### Why are `revert` and `chore` valid types in the check pattern of cz conventional_commits but not types we can select? `revert` and `chore` are added to the "pattern" in `cz check` in order to prevent backward errors, but officially they are not part of conventional commits, we are using the latest [types from Angular](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#type) (they used to but were removed). -However, you can create a customized `cz` with those extra types. (See [Customization](https://commitizen-tools.github.io/commitizen/customization.html)) +However, you can create a customized `cz` with those extra types. (See [Customization](https://commitizen-tools.github.io/commitizen/customization)) See more discussion in issue [#142](https://github.com/commitizen-tools/commitizen/issues/142) and [#36](https://github.com/commitizen-tools/commitizen/issues/36) From 50d57acc8137ae9f7ff470c86e1e9009467669d3 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Wed, 14 Jul 2021 15:01:37 +0000 Subject: [PATCH 388/427] =?UTF-8?q?bump:=20version=202.17.12=20=E2=86=92?= =?UTF-8?q?=202.17.13?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 ++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddfa7f2cfa..25a748580c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,6 @@ +## v2.17.13 (2021-07-14) + ## v2.17.12 (2021-07-06) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 2943092d1b..90c07a41b7 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.17.12" +__version__ = "2.17.13" diff --git a/pyproject.toml b/pyproject.toml index a3dcdfe264..d4c844edd4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.17.12" +version = "2.17.13" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.17.12" +version = "2.17.13" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From d5eeef676e649b57b544f81df7fff19f0a4d24fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 21 Nov 2020 18:52:39 +0100 Subject: [PATCH 389/427] ci: run tests on linux, mac and windows --- .github/workflows/pythonpackage.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 3fa8855279..c7eb887399 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -4,12 +4,12 @@ on: [pull_request] jobs: python-check: - runs-on: ubuntu-latest strategy: max-parallel: 4 matrix: python-version: [3.6, 3.7, 3.8] - + platform: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.platform }} steps: - uses: actions/checkout@v2 with: From a074a79697744d995fbc3459766dec7705b80a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Fraire=20Willemo=C3=ABs?= <santiwilly@gmail.com> Date: Sat, 21 Nov 2020 18:55:24 +0100 Subject: [PATCH 390/427] ci: run tests on oldest py3.6 and last 2 py3.9 and py3.8 --- .github/workflows/pythonpackage.yml | 3 +-- pyproject.toml | 4 +++- tests/commands/conftest.py | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index c7eb887399..82078d4b93 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -5,9 +5,8 @@ on: [pull_request] jobs: python-check: strategy: - max-parallel: 4 matrix: - python-version: [3.6, 3.7, 3.8] + python-version: [3.6, 3.8, 3.9] platform: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.platform }} steps: diff --git a/pyproject.toml b/pyproject.toml index d4c844edd4..40346652df 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,7 +63,7 @@ flake8 = "^3.6" pytest-cov = "^2.6" pytest-mock = "^2.0" codecov = "^2.0" -mypy = "^0.770" +mypy = "0.910" mkdocs = "^1.0" mkdocs-material = "^4.1" isort = "^5.7.0" @@ -72,6 +72,8 @@ pydocstyle = "^5.0.2" pre-commit = "^2.6.0" pytest-regressions = "^2.2.0" pytest-freezegun = "^0.4.2" +types-PyYAML = "^5.4.3" +types-termcolor = "^0.1.1" [tool.poetry.scripts] cz = "commitizen.cli:main" diff --git a/tests/commands/conftest.py b/tests/commands/conftest.py index 25bab04464..faae727918 100644 --- a/tests/commands/conftest.py +++ b/tests/commands/conftest.py @@ -13,11 +13,11 @@ def config(): return _config -@pytest.fixture() +@pytest.fixture() # type: ignore def changelog_path() -> str: return os.path.join(os.getcwd(), "CHANGELOG.md") -@pytest.fixture() +@pytest.fixture() # type: ignore def config_path() -> str: return os.path.join(os.getcwd(), "pyproject.toml") From 078183510ba415457532b6e811a2e398ab9a5ea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fraire=20Willemo=C3=ABs=2C=20Santiago?= <santiwilly@gmail.com> Date: Mon, 2 Aug 2021 09:51:23 +0200 Subject: [PATCH 391/427] style: remove unused mypy comment --- commitizen/commands/init.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commitizen/commands/init.py b/commitizen/commands/init.py index eed9b83ae4..d4a4180aa3 100644 --- a/commitizen/commands/init.py +++ b/commitizen/commands/init.py @@ -51,7 +51,7 @@ def __call__(self): def _ask_config_path(self) -> str: name = questionary.select( "Please choose a supported config file: (default: pyproject.toml)", - choices=config_files, # type: ignore + choices=config_files, default="pyproject.toml", style=self.cz.style, ).ask() From 33c3c49c252890db7859f2cad76525fd86b8eaa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fraire=20Willemo=C3=ABs=2C=20Santiago?= <santiwilly@gmail.com> Date: Tue, 27 Jul 2021 08:12:39 +0200 Subject: [PATCH 392/427] docs(contributing): do not request modifications to changelog --- docs/contributing.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/contributing.md b/docs/contributing.md index 4f04978a25..b106edc73c 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -15,7 +15,9 @@ If you're a first-time contributor, you can check the issues with [good first is 5. Check out a new branch and add your modification. 6. Add test cases for all your changes. (We use [CodeCov](https://codecov.io/) to ensure our test coverage does not drop.) -7. Use [commitizen](https://github.com/commitizen-tools/commitizen) to do git commit. +7. Use [commitizen](https://github.com/commitizen-tools/commitizen) to do git commit. We follow [conventional commmits][conventional-commmits] 8. Run `./scripts/format` and `./scripts/test` to ensure you follow the coding style and the tests pass. -9. Update `README.md` and `CHANGELOG.md` for your changes. +9. Update `README.md`. Do **not** update the `CHANGELOG.md`, it will be automatically created after merging to `master`. 10. Send a [pull request](https://github.com/commitizen-tools/commitizen/pulls) 🙏 + +[conventional-commmits]: https://www.conventionalcommits.org/ From cfec0f5cbbb86176e372889051289e21c10a5518 Mon Sep 17 00:00:00 2001 From: Zev Isert <dev@zevisert.ca> Date: Fri, 16 Jul 2021 19:09:45 -0700 Subject: [PATCH 393/427] feat(prompt): add keyboard shortcuts with config option --- .../conventional_commits.py | 17 +++++++++++++++-- commitizen/defaults.py | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index 6ac62d5ec1..d51e8bdf20 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -45,16 +45,23 @@ def questions(self) -> List[Dict[str, Any]]: "type": "list", "name": "prefix", "message": "Select the type of change you are committing", + "use_shortcuts": self.config.settings['use_shortcuts'], "choices": [ { "value": "fix", "name": "fix: A bug fix. Correlates with PATCH in SemVer", + "key": "x", }, { "value": "feat", "name": "feat: A new feature. Correlates with MINOR in SemVer", + "key": "f", + }, + { + "value": "docs", + "name": "docs: Documentation only changes", + "key": "d", }, - {"value": "docs", "name": "docs: Documentation only changes"}, { "value": "style", "name": ( @@ -62,6 +69,7 @@ def questions(self) -> List[Dict[str, Any]]: "meaning of the code (white-space, formatting," " missing semi-colons, etc)" ), + "key": "s", }, { "value": "refactor", @@ -69,16 +77,19 @@ def questions(self) -> List[Dict[str, Any]]: "refactor: A code change that neither fixes " "a bug nor adds a feature" ), + "key": "r", }, { "value": "perf", "name": "perf: A code change that improves performance", + "key": "p", }, { "value": "test", "name": ( "test: Adding missing or correcting " "existing tests" ), + "key": "t", }, { "value": "build", @@ -86,6 +97,7 @@ def questions(self) -> List[Dict[str, Any]]: "build: Changes that affect the build system or " "external dependencies (example scopes: pip, docker, npm)" ), + "key": "b", }, { "value": "ci", @@ -93,7 +105,8 @@ def questions(self) -> List[Dict[str, Any]]: "ci: Changes to our CI configuration files and " "scripts (example scopes: GitLabCI)" ), - }, + "key": "c", + } ], }, { diff --git a/commitizen/defaults.py b/commitizen/defaults.py index 83f2ca4636..5d21f67a98 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -21,6 +21,7 @@ "changelog_incremental": False, "changelog_start_rev": None, "update_changelog_on_bump": False, + "use_shortcuts": False, } MAJOR = "MAJOR" From 3910f844f45effa8d3e9fe8475fbb38c22975a30 Mon Sep 17 00:00:00 2001 From: Zev Isert <dev@zevisert.ca> Date: Fri, 6 Aug 2021 11:39:15 -0700 Subject: [PATCH 394/427] test: update tests for keyboard shortcuts Only testing that cz_conventional_commits has keyboard shortcuts configured, and that the use_shortcuts config option is known. Actually mocking and asserting against what's written to stdout is a footgun #406, #380 --- tests/test_conf.py | 2 ++ tests/test_cz_conventional_commits.py | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/tests/test_conf.py b/tests/test_conf.py index f05603cfe4..786af25756 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -46,6 +46,7 @@ "changelog_incremental": False, "changelog_start_rev": None, "update_changelog_on_bump": False, + "use_shortcuts": False, } _new_settings = { @@ -59,6 +60,7 @@ "changelog_incremental": False, "changelog_start_rev": None, "update_changelog_on_bump": False, + "use_shortcuts": False, } _read_settings = { diff --git a/tests/test_cz_conventional_commits.py b/tests/test_cz_conventional_commits.py index e43284a121..6a3b538ed3 100644 --- a/tests/test_cz_conventional_commits.py +++ b/tests/test_cz_conventional_commits.py @@ -62,6 +62,15 @@ def test_questions(config): assert isinstance(questions[0], dict) +def test_choices_all_have_keyboard_shortcuts(config): + conventional_commits = ConventionalCommitsCz(config) + questions = conventional_commits.questions() + + list_questions = (q for q in questions if q['type'] == "list") + for select in list_questions: + assert all('key' in choice for choice in select['choices']) + + def test_small_answer(config): conventional_commits = ConventionalCommitsCz(config) answers = { From 6820271877fc3c7176bf842dc513ef5be1305882 Mon Sep 17 00:00:00 2001 From: Zev Isert <dev@zevisert.ca> Date: Mon, 9 Aug 2021 09:42:35 -0700 Subject: [PATCH 395/427] style: formatting --- commitizen/cz/conventional_commits/conventional_commits.py | 4 ++-- commitizen/defaults.py | 2 +- tests/test_cz_conventional_commits.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index d51e8bdf20..fea3d61848 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -45,7 +45,7 @@ def questions(self) -> List[Dict[str, Any]]: "type": "list", "name": "prefix", "message": "Select the type of change you are committing", - "use_shortcuts": self.config.settings['use_shortcuts'], + "use_shortcuts": self.config.settings["use_shortcuts"], "choices": [ { "value": "fix", @@ -106,7 +106,7 @@ def questions(self) -> List[Dict[str, Any]]: "scripts (example scopes: GitLabCI)" ), "key": "c", - } + }, ], }, { diff --git a/commitizen/defaults.py b/commitizen/defaults.py index 5d21f67a98..e460bbd6f7 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -21,7 +21,7 @@ "changelog_incremental": False, "changelog_start_rev": None, "update_changelog_on_bump": False, - "use_shortcuts": False, + "use_shortcuts": False, } MAJOR = "MAJOR" diff --git a/tests/test_cz_conventional_commits.py b/tests/test_cz_conventional_commits.py index 6a3b538ed3..b84144e94c 100644 --- a/tests/test_cz_conventional_commits.py +++ b/tests/test_cz_conventional_commits.py @@ -66,9 +66,9 @@ def test_choices_all_have_keyboard_shortcuts(config): conventional_commits = ConventionalCommitsCz(config) questions = conventional_commits.questions() - list_questions = (q for q in questions if q['type'] == "list") + list_questions = (q for q in questions if q["type"] == "list") for select in list_questions: - assert all('key' in choice for choice in select['choices']) + assert all("key" in choice for choice in select["choices"]) def test_small_answer(config): From e333537b3dd51216f674db4711608de720ebf690 Mon Sep 17 00:00:00 2001 From: Zev Isert <dev@zevisert.ca> Date: Wed, 11 Aug 2021 18:40:41 -0700 Subject: [PATCH 396/427] refactor(shortcuts): move check for shortcut config setting to apply to any list select --- commitizen/commands/commit.py | 2 ++ commitizen/cz/conventional_commits/conventional_commits.py | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index 4c6f7aa03c..ac646a0220 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -46,6 +46,8 @@ def prompt_commit_questions(self) -> str: # Prompt user for the commit message cz = self.cz questions = cz.questions() + for question in filter(lambda q: q['type'] == 'list', questions): + question["use_shortcuts"] = self.config.settings["use_shortcuts"] try: answers = questionary.prompt(questions, style=cz.style) except ValueError as err: diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index fea3d61848..61f7b7f94b 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -45,7 +45,6 @@ def questions(self) -> List[Dict[str, Any]]: "type": "list", "name": "prefix", "message": "Select the type of change you are committing", - "use_shortcuts": self.config.settings["use_shortcuts"], "choices": [ { "value": "fix", From 90c9918e259fd3956e64be80e1358c1cfb75a7d2 Mon Sep 17 00:00:00 2001 From: Zev Isert <dev@zevisert.ca> Date: Wed, 11 Aug 2021 18:43:13 -0700 Subject: [PATCH 397/427] docs(shortcuts): update to include info about keyboard shortcut options --- docs/config.md | 28 +++++++++++++++--------- docs/customization.md | 51 +++++++++++++++++++++++++------------------ 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/docs/config.md b/docs/config.md index 204edcf887..eee90e1dcc 100644 --- a/docs/config.md +++ b/docs/config.md @@ -122,13 +122,21 @@ commitizen: ## Settings -| Variable | Type | Default | Description | -| -------- | ---- | ------- | ----------- | -| `name` | `str` | `"cz_conventional_commits"` | Name of the committing rules to use | -| `version` | `str` | `None` | Current version. Example: "0.1.2" | -| `version_files` | `list` | `[ ]` | Files were the version will be updated. A pattern to match a line, can also be specified, separated by `:` [See more](https://commitizen-tools.github.io/commitizen/bump/#version_files) | -| `tag_format` | `str` | `None` | Format for the git tag, useful for old projects, that use a convention like `"v1.2.1"`. [See more](https://commitizen-tools.github.io/commitizen/bump/#tag_format) | -| `bump_message` | `str` | `None` | Create custom commit message, useful to skip ci. [See more](https://commitizen-tools.github.io/commitizen/bump/#bump_message) | -| `changelog_file` | `str` | `CHANGELOG.md` | filename of exported changelog | -| `style` | `list` | see above | Style for the prompts (It will merge this value with default style.) [See More (Styling your prompts with your favorite colors)](https://github.com/tmbo/questionary#additional-features) | -| `customize` | `dict` | `None` | **This is only supported when config through `toml`.** Custom rules for committing and bumping. [See more](https://commitizen-tools.github.io/commitizen/customization/) | +| Variable | Type | Default | Description | +| ---------------- | ------ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `name` | `str` | `"cz_conventional_commits"` | Name of the committing rules to use | +| `version` | `str` | `None` | Current version. Example: "0.1.2" | +| `version_files` | `list` | `[ ]` | Files were the version will be updated. A pattern to match a line, can also be specified, separated by `:` [See more](version_files) | +| `tag_format` | `str` | `None` | Format for the git tag, useful for old projects, that use a convention like `"v1.2.1"`. [See more](tag_format) | +| `bump_message` | `str` | `None` | Create custom commit message, useful to skip ci. [See more](bump_message) | +| `changelog_file` | `str` | `CHANGELOG.md` | filename of exported changelog | +| `style` | `list` | see above | Style for the prompts (It will merge this value with default style.) [See More (Styling your prompts with your favorite colors)](additional-features) | +| `customize` | `dict` | `None` | **This is only supported when config through `toml`.** Custom rules for committing and bumping. [See more](customization) | +| `use_shortcuts` | `bool` | `false` | If enabled, commitizen will show keyboard shortcuts when selecting from a list. Define a `key` for each of your choices to set the key. [See more](shortcuts) | + +[version_files]: https://commitizen-tools.github.io/commitizen/bump/#version_files +[tag_format]: https://commitizen-tools.github.io/commitizen/bump/#tag_format +[bump_message]: https://commitizen-tools.github.io/commitizen/bump/#bump_message +[additional-features]: https://github.com/tmbo/questionary#additional-features +[customization]: https://commitizen-tools.github.io/commitizen/customization/ +[shortcuts]: https://commitizen-tools.github.io/commitizen/customization/#shortcut-keys diff --git a/docs/customization.md b/docs/customization.md index 3492d8288c..b96c459e41 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -138,30 +138,39 @@ commitizen: ### Customize configuration -| Parameter | Type | Default | Description | -| ------------------ | ------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `questions` | `dict` | `None` | Questions regarding the commit message. Detailed below. | -| `message_template` | `str` | `None` | The template for generating message from the given answers. `message_template` should either follow [Jinja2](https://jinja.palletsprojects.com/en/2.10.x/) formatting specification, and all the variables in this template should be defined in `name` in `questions` | -| `example` | `str` | `None` | (OPTIONAL) Provide an example to help understand the style. Used by `cz example`. | -| `schema` | `str` | `None` | (OPTIONAL) Show the schema used. Used by `cz schema`. | -| `schema_pattern` | `str` | `None` | (OPTIONAL) The regular expression used to do commit message validation. Used by `cz check`. | -| `info_path` | `str` | `None` | (OPTIONAL) The path to the file that contains explanation of the commit rules. Used by `cz info`. If not provided `cz info`, will load `info` instead. | -| `info` | `str` | `None` | (OPTIONAL) Explanation of the commit rules. Used by `cz info`. | -| `bump_map` | `dict` | `None` | (OPTIONAL) Dictionary mapping the extracted information to a `SemVer` increment type (`MAJOR`, `MINOR`, `PATCH`) | -| `bump_pattern` | `str` | `None` | (OPTIONAL) Regex to extract information from commit (subject and body) | -| `change_type_order`| `str` | `None` | (OPTIONAL) List of strings used to order the Changelog. All other types will be sorted alphabetically. Default is `["BREAKING CHANGE", "feat", "fix", "refactor", "perf"]` | - +| Parameter | Type | Default | Description | +| ------------------- | ------ | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `questions` | `dict` | `None` | Questions regarding the commit message. Detailed below. | +| `message_template` | `str` | `None` | The template for generating message from the given answers. `message_template` should either follow [Jinja2][jinja2] formatting specification, and all the variables in this template should be defined in `name` in `questions` | +| `example` | `str` | `None` | (OPTIONAL) Provide an example to help understand the style. Used by `cz example`. | +| `schema` | `str` | `None` | (OPTIONAL) Show the schema used. Used by `cz schema`. | +| `schema_pattern` | `str` | `None` | (OPTIONAL) The regular expression used to do commit message validation. Used by `cz check`. | +| `info_path` | `str` | `None` | (OPTIONAL) The path to the file that contains explanation of the commit rules. Used by `cz info`. If not provided `cz info`, will load `info` instead. | +| `info` | `str` | `None` | (OPTIONAL) Explanation of the commit rules. Used by `cz info`. | +| `bump_map` | `dict` | `None` | (OPTIONAL) Dictionary mapping the extracted information to a `SemVer` increment type (`MAJOR`, `MINOR`, `PATCH`) | +| `bump_pattern` | `str` | `None` | (OPTIONAL) Regex to extract information from commit (subject and body) | +| `change_type_order` | `str` | `None` | (OPTIONAL) List of strings used to order the Changelog. All other types will be sorted alphabetically. Default is `["BREAKING CHANGE", "feat", "fix", "refactor", "perf"]` | + +[jinja2]: https://jinja.palletsprojects.com/en/2.10.x/ #### Detailed `questions` content -| Parameter | Type | Default | Description | -| --------- | ------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| `type` | `str` | `None` | The type of questions. Valid type: `list`, `input` and etc. [See More](https://github.com/tmbo/questionary#different-question-types) | -| `name` | `str` | `None` | The key for the value answered by user. It's used in `message_template` | -| `message` | `str` | `None` | Detail description for the question. | -| `choices` | `list` | `None` | (OPTIONAL) The choices when `type = list`. Either use a list of values or a list of dicitionaries with `name` and `value` keys. See examples above. | -| `default` | `Any` | `None` | (OPTIONAL) The default value for this question. | -| `filter` | `str` | `None` | (Optional) Validator for user's answer. **(Work in Progress)** | +| Parameter | Type | Default | Description | +| --------- | ------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `type` | `str` | `None` | The type of questions. Valid type: `list`, `input` and etc. [See More][different-question-types] | +| `name` | `str` | `None` | The key for the value answered by user. It's used in `message_template` | +| `message` | `str` | `None` | Detail description for the question. | +| `choices` | `list` | `None` | (OPTIONAL) The choices when `type = list`. Either use a list of values or a list of dictionaries with `name` and `value` keys. Keyboard shortcuts can be defined via `key`. See examples above. | +| `default` | `Any` | `None` | (OPTIONAL) The default value for this question. | +| `filter` | `str` | `None` | (Optional) Validator for user's answer. **(Work in Progress)** | + +[different-question-types]: https://github.com/tmbo/questionary#different-question-types + +#### Shortcut keys +When the [`use_shortcuts`](https://commitizen-tools.github.io/commitizen/config/#settings) config option is enabled, commitizen can show and use keyboard shortcuts to select items from lists directly. +For example, when using the `cz_conventional_commits` commitizen template, shortcut keys are shown when selecting the commit type. Unless otherwise defined, keyboard shortcuts will be numbered automatically. +To specify keyboard shortcuts for your custom choices, provide the shortcut using the `key` parameter in dictionary form for each choice you would like to customize. + ## 2. Customize through customizing a class The basic steps are: From dedcb2dd3a54d0b4011c7a68abdae74cfb9125c4 Mon Sep 17 00:00:00 2001 From: Zev Isert <dev@zevisert.ca> Date: Wed, 11 Aug 2021 18:45:20 -0700 Subject: [PATCH 398/427] style: forgot to run black --- commitizen/commands/commit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index ac646a0220..bad47dd572 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -46,7 +46,7 @@ def prompt_commit_questions(self) -> str: # Prompt user for the commit message cz = self.cz questions = cz.questions() - for question in filter(lambda q: q['type'] == 'list', questions): + for question in filter(lambda q: q["type"] == "list", questions): question["use_shortcuts"] = self.config.settings["use_shortcuts"] try: answers = questionary.prompt(questions, style=cz.style) From cf646706b53bbd7921b291d24063b8d7eb300899 Mon Sep 17 00:00:00 2001 From: GitHub Action <action@github.com> Date: Fri, 13 Aug 2021 09:16:08 +0000 Subject: [PATCH 399/427] =?UTF-8?q?bump:=20version=202.17.13=20=E2=86=92?= =?UTF-8?q?=202.18.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 10 ++++++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25a748580c..a9b383bac3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,14 @@ +## v2.18.0 (2021-08-13) + +### Refactor + +- **shortcuts**: move check for shortcut config setting to apply to any list select + +### Feat + +- **prompt**: add keyboard shortcuts with config option + ## v2.17.13 (2021-07-14) ## v2.17.12 (2021-07-06) diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 90c07a41b7..6ebac24f89 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.17.13" +__version__ = "2.18.0" diff --git a/pyproject.toml b/pyproject.toml index 40346652df..c72e717fdd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.17.13" +version = "2.18.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.17.13" +version = "2.18.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From d1e6dad31889646fcbd94ed0ba19aea8077a32d4 Mon Sep 17 00:00:00 2001 From: falko-apheris <86360866+falko-apheris@users.noreply.github.com> Date: Fri, 13 Aug 2021 14:32:22 +0200 Subject: [PATCH 400/427] docs: add docs for 3rd party module cz-github-jira-conventional --- docs/third-party-commitizen.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/third-party-commitizen.md b/docs/third-party-commitizen.md index 7c27e75d80..ff6144e6b9 100644 --- a/docs/third-party-commitizen.md +++ b/docs/third-party-commitizen.md @@ -11,6 +11,17 @@ meaningful way. It can be installed with `pip install conventional-JIRA`. +### [GitHub JIRA Conventional](https://pypi.org/project/cz-github-jira-conventional/) + +This plugin extends the commitizen tools by: +- requiring a JIRA issue id in the commit message +- creating links to GitHub commits in the CHANGELOG.md +- creating links to JIRA issues in the CHANGELOG.md + +It can be installed with `cz-github-jira-conventional`. + +For installation instructions (configuration and pre-commit) please visit https://github.com/apheris/cz-github-jira-conventional + ### [Commitizen emoji](https://pypi.org/project/commitizen-emoji/) Just like *conventional commit* format, but with emojis and optionally time spent and related tasks. From 79b31566ab1e66560856ae1e813f702264aba06b Mon Sep 17 00:00:00 2001 From: Bryan Dady <bryan@dady.us> Date: Fri, 10 Sep 2021 23:36:10 -0600 Subject: [PATCH 401/427] Address typos and layout Resolve some minor typos and line up long line wrap point --- docs/tutorials/writing_commits.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/tutorials/writing_commits.md b/docs/tutorials/writing_commits.md index cf6b6bda11..4cf377a8c1 100644 --- a/docs/tutorials/writing_commits.md +++ b/docs/tutorials/writing_commits.md @@ -1,20 +1,21 @@ -For this project to work well in your pipeline, a commit convention -must be followed. +For this project to work well in your pipeline, a commit convention must be followed. -By default commitizen uses the known [conventional commits][conventional_commits], but you can create -your own following the docs information over [customization][customization]. +By default commitizen uses the known [conventional commits][conventional_commits], but +you can create your own following the docs information over at +[customization][customization]. ## Conventional commits If you are using [conventional commits][conventional_commits], the most important -thing to know is that you must begin your commits with at least one of these tags: `fix`, `feat`. And if you introduce a breaking change, then, you must +thing to know is that you must begin your commits with at least one of these tags: +`fix`, `feat`. And if you introduce a breaking change, then, you must add to your commit body the following `BREAKING CHANGE`. Using these 3 keywords will allow the proper identification of the semantic version. Of course, there are other keywords, but I'll leave it to the reader to explore them. ## Writing commits -Not to the important part, when writing commits, it's important to think about: +Now to the important part, when writing commits, it's important to think about: - Your future self - Your colleagues @@ -27,8 +28,10 @@ understand what happened. - **Keep the message short**: Makes the list of commits more readable (~50 chars). - **Talk imperative**: Follow this rule: `If applied, this commit will <commit message>` - **Think about the CHANGELOG**: Your commits will probably end up in the changelog - so try writing for it, but also keep in mind that you can skip sending commits to the CHANGELOG by using different keywords (like `build`). -- **Use a commit per new feature**: if you introduce multiple things related to the same commit, squash them. This is useful for auto-generating CHANGELOG. + so try writing for it, but also keep in mind that you can skip sending commits to the + CHANGELOG by using different keywords (like `build`). +- **Use a commit per new feature**: if you introduce multiple things related to the same + commit, squash them. This is useful for auto-generating CHANGELOG. | Do's | Don'ts | | ---- | ------ | From e92e07f348a37056215a55c6ce686999d69f931b Mon Sep 17 00:00:00 2001 From: Xavier Moreno <xaviml.93@gmail.com> Date: Sat, 11 Sep 2021 17:36:33 +0200 Subject: [PATCH 402/427] fix(commit): correct the stage checker before commiting related to #418 --- commitizen/git.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/commitizen/git.py b/commitizen/git.py index 2904d6cb05..080c5a6cb9 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -155,9 +155,8 @@ def find_git_project_root() -> Optional[Path]: def is_staging_clean() -> bool: """Check if staing is clean.""" - c = cmd.run("git diff --no-ext-diff --name-only") - c_cached = cmd.run("git diff --no-ext-diff --cached --name-only") - return not (bool(c.out) or bool(c_cached.out)) + c = cmd.run("git diff --no-ext-diff --cached --name-only") + return not bool(c.out) def is_git_project() -> bool: From a2d6312ee174635c980b2bec6af3d82b5709ae7c Mon Sep 17 00:00:00 2001 From: Xavier Moreno <xaviml.93@gmail.com> Date: Sun, 12 Sep 2021 12:56:38 +0200 Subject: [PATCH 403/427] test(git): extend test for is_staging_clean --- commitizen/git.py | 2 +- tests/test_git.py | 22 ++++++++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/commitizen/git.py b/commitizen/git.py index 080c5a6cb9..b196f15115 100644 --- a/commitizen/git.py +++ b/commitizen/git.py @@ -154,7 +154,7 @@ def find_git_project_root() -> Optional[Path]: def is_staging_clean() -> bool: - """Check if staing is clean.""" + """Check if staging is clean.""" c = cmd.run("git diff --no-ext-diff --cached --name-only") return not bool(c.out) diff --git a/tests/test_git.py b/tests/test_git.py index dc8023b956..c764a6d65a 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -70,7 +70,7 @@ def test_get_commits_author_and_email(): create_file_and_commit("fix: username exception") commit = git.get_commits()[0] - assert commit.author is not "" + assert commit.author != "" assert "@" in commit.author_email @@ -176,12 +176,30 @@ def test_get_latest_tag_name(tmp_commitizen_project): assert tag_name == "1.0" -def test_is_staging_clean(tmp_commitizen_project): +def test_is_staging_clean_when_adding_file(tmp_commitizen_project): + with tmp_commitizen_project.as_cwd(): + assert git.is_staging_clean() is True + + cmd.run("touch test_file") + + assert git.is_staging_clean() is True + + cmd.run("git add test_file") + + assert git.is_staging_clean() is False + + +def test_is_staging_clean_when_updating_file(tmp_commitizen_project): with tmp_commitizen_project.as_cwd(): assert git.is_staging_clean() is True cmd.run("touch test_file") cmd.run("git add test_file") + cmd.run("git commit -m 'add test_file'") cmd.run("echo 'test' > test_file") + assert git.is_staging_clean() is True + + cmd.run("git add test_file") + assert git.is_staging_clean() is False From 4309813974b6be72a246d47fc77f4c7f8ef64be1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com> Date: Sun, 12 Sep 2021 14:11:07 +0000 Subject: [PATCH 404/427] =?UTF-8?q?bump:=20version=202.18.0=20=E2=86=92=20?= =?UTF-8?q?2.18.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9b383bac3..a7d0b96567 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +## v2.18.1 (2021-09-12) + +### Fix + +- **commit**: correct the stage checker before commiting + ## v2.18.0 (2021-08-13) ### Refactor diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 6ebac24f89..68a0e5125c 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.18.0" +__version__ = "2.18.1" diff --git a/pyproject.toml b/pyproject.toml index c72e717fdd..77b882f622 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.18.0" +version = "2.18.1" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.18.0" +version = "2.18.1" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 9924180b6f92c558d4f58b5472ae1712057b166d Mon Sep 17 00:00:00 2001 From: Rambaud Pierrick <12rambau@users.noreply.github.com> Date: Wed, 15 Sep 2021 14:26:01 +0200 Subject: [PATCH 405/427] doc: inverse major and minor In the example, the major an minor keyword were set in a strange order. I changed it to stay consistent with PEP --- docs/bump.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/bump.md b/docs/bump.md index bf3b207cd6..38e4f5272b 100644 --- a/docs/bump.md +++ b/docs/bump.md @@ -199,7 +199,7 @@ In your `pyproject.toml` or `.cz.toml` ```toml [tool.commitizen] -tag_format = "v$minor.$major.$patch$prerelease" +tag_format = "v$major.$minor.$patch$prerelease" ``` The variables must be preceded by a `$` sign. From ca0e4bcd0a2b3d6dbf9beeb9334c823b4e5cd9fc Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 26 Sep 2021 16:09:01 +0800 Subject: [PATCH 406/427] fix(cli): handle argparse different behavior after python 3.9 argparse raises TypeError when non exist command is provided on Python < 3.9 but raise SystemExit with exit code == 2 on Python 3.9 this error does not break anything obviously from the user perspective, but will break our existing test 429 --- commitizen/cli.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index a5c336f9fd..2fb482094b 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -286,8 +286,13 @@ def main(): # This is for the command required constraint in 2.0 try: args = parser.parse_args() - except TypeError: - raise NoCommandFoundError() + except (TypeError, SystemExit) as e: + # https://github.com/commitizen-tools/commitizen/issues/429 + # argparse raises TypeError when non exist command is provided on Python < 3.9 + # but raise SystemExit with exit code == 2 on Python 3.9 + if isinstance(e, TypeError) or (isinstance(e, SystemExit) and e.code == 2): + raise NoCommandFoundError() + raise e if args.name: conf.update({"name": args.name}) From ca3145269ff635aba507af56103a416361f7f87d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com> Date: Mon, 27 Sep 2021 06:41:05 +0000 Subject: [PATCH 407/427] =?UTF-8?q?bump:=20version=202.18.1=20=E2=86=92=20?= =?UTF-8?q?2.18.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7d0b96567..2af38096af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +## v2.18.2 (2021-09-27) + +### Fix + +- **cli**: handle argparse different behavior after python 3.9 + ## v2.18.1 (2021-09-12) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 68a0e5125c..855930a227 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.18.1" +__version__ = "2.18.2" diff --git a/pyproject.toml b/pyproject.toml index 77b882f622..2639e487c8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.18.1" +version = "2.18.2" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.18.1" +version = "2.18.2" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 609cacdb1580d540d26e3486ac59a858a1546fbc Mon Sep 17 00:00:00 2001 From: Sarthak Sharma <sarthaksharma2199@outlook.com> Date: Mon, 27 Sep 2021 13:38:19 +0530 Subject: [PATCH 408/427] feat: utility for showing system information command to show system info output for bug reports Issue #426 --- .github/ISSUE_TEMPLATE/bug_report.md | 9 +++++- commitizen/cli.py | 6 ++++ commitizen/commands/version.py | 11 ++++++- tests/commands/test_version_command.py | 42 ++++++++++++++++++++++---- 4 files changed, 60 insertions(+), 8 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index bfd26c9265..73d632fd13 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -28,11 +28,18 @@ If applicable, add screenshots to help explain your problem. ## Environment <!-- +For older commitizen versions, please include the +output of the following commands manually: + cz version python --version python3 -c "import platform; print(platform.system())" --> - +Add output of the following command to include the following - commitizen version: - python version: - operating system: +```bash +cz version --report +``` + diff --git a/commitizen/cli.py b/commitizen/cli.py index 2fb482094b..e1bad367e7 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -227,6 +227,12 @@ ), "func": commands.Version, "arguments": [ + { + "name": ["-r", "--report"], + "help": "get system information for reporting bugs", + "action": "store_true", + "exclusive_group": "group1", + }, { "name": ["-p", "--project"], "help": "get the version of the current project", diff --git a/commitizen/commands/version.py b/commitizen/commands/version.py index 143a0c7351..dc47e7aa0c 100644 --- a/commitizen/commands/version.py +++ b/commitizen/commands/version.py @@ -1,3 +1,6 @@ +import platform +import sys + from commitizen import out from commitizen.__version__ import __version__ from commitizen.config import BaseConfig @@ -9,9 +12,15 @@ class Version: def __init__(self, config: BaseConfig, *args): self.config: BaseConfig = config self.parameter = args[0] + self.operating_system = platform.system() + self.python_version = sys.version def __call__(self): - if self.parameter.get("project"): + if self.parameter.get("report"): + out.write(f"Commitizen Version: {__version__}") + out.write(f"Python Version: {self.python_version}") + out.write(f"Operating System: {self.operating_system}") + elif self.parameter.get("project"): version = self.config.settings["version"] if version: out.write(f"{version}") diff --git a/tests/commands/test_version_command.py b/tests/commands/test_version_command.py index 527c0b53f1..7e6ec3c851 100644 --- a/tests/commands/test_version_command.py +++ b/tests/commands/test_version_command.py @@ -1,42 +1,72 @@ +import platform +import sys + from commitizen import commands from commitizen.__version__ import __version__ def test_version_for_showing_project_version(config, capsys): # No version exist - commands.Version(config, {"project": True, "commitizen": False, "verbose": False})() + commands.Version( + config, + {"report": False, "project": True, "commitizen": False, "verbose": False}, + )() captured = capsys.readouterr() assert "No project information in this project." in captured.err config.settings["version"] = "v0.0.1" - commands.Version(config, {"project": True, "commitizen": False, "verbose": False})() + commands.Version( + config, + {"report": False, "project": True, "commitizen": False, "verbose": False}, + )() captured = capsys.readouterr() assert "v0.0.1" in captured.out def test_version_for_showing_commitizen_version(config, capsys): - commands.Version(config, {"project": False, "commitizen": True, "verbose": False})() + commands.Version( + config, + {"report": False, "project": False, "commitizen": True, "verbose": False}, + )() captured = capsys.readouterr() assert f"{__version__}" in captured.out # default showing commitizen version commands.Version( - config, {"project": False, "commitizen": False, "verbose": False} + config, + {"report": False, "project": False, "commitizen": False, "verbose": False}, )() captured = capsys.readouterr() assert f"{__version__}" in captured.out def test_version_for_showing_both_versions(config, capsys): - commands.Version(config, {"project": False, "commitizen": False, "verbose": True})() + commands.Version( + config, + {"report": False, "project": False, "commitizen": False, "verbose": True}, + )() captured = capsys.readouterr() assert f"Installed Commitizen Version: {__version__}" in captured.out assert "No project information in this project." in captured.err config.settings["version"] = "v0.0.1" - commands.Version(config, {"project": False, "commitizen": False, "verbose": True})() + commands.Version( + config, + {"report": False, "project": False, "commitizen": False, "verbose": True}, + )() captured = capsys.readouterr() expected_out = ( f"Installed Commitizen Version: {__version__}\n" f"Project Version: v0.0.1" ) assert expected_out in captured.out + + +def test_version_for_showing_commitizen_system_info(config, capsys): + commands.Version( + config, + {"report": True, "project": False, "commitizen": False, "verbose": False}, + )() + captured = capsys.readouterr() + assert f"Commitizen Version: {__version__}" in captured.out + assert f"Python Version: {sys.version}" in captured.out + assert f"Operating System: {platform.system()}" in captured.out From 976d5d24cc66e24c9c5c9ba871f6b9567ab6c9b5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com> Date: Mon, 27 Sep 2021 14:43:10 +0000 Subject: [PATCH 409/427] =?UTF-8?q?bump:=20version=202.18.2=20=E2=86=92=20?= =?UTF-8?q?2.19.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 ++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2af38096af..42630e4043 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +## v2.19.0 (2021-09-27) + +### Feat + +- utility for showing system information + ## v2.18.2 (2021-09-27) ### Fix diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 855930a227..326b86ff29 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.18.2" +__version__ = "2.19.0" diff --git a/pyproject.toml b/pyproject.toml index 2639e487c8..c3a8a820cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.18.2" +version = "2.19.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.18.2" +version = "2.19.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 7b7b0c97a3371ea105833b5862592a45d02d6d51 Mon Sep 17 00:00:00 2001 From: Angelo Mantellini <manangel@cisco.com> Date: Wed, 29 Sep 2021 18:37:54 +0200 Subject: [PATCH 410/427] feat: add signoff parameter to commit command command to sign off the commit, equivalent to git commit -s --- commitizen/cli.py | 5 +++++ commitizen/commands/commit.py | 7 ++++++- tests/commands/test_commit_command.py | 20 ++++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index e1bad367e7..215d8faf82 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -49,6 +49,11 @@ "action": "store_true", "help": "show output to stdout, no commit, no modified files", }, + { + "name": "--signoff", + "action": "store_true", + "help": "Sign off the commit", + }, ], }, { diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index bad47dd572..a4c0301732 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -78,7 +78,12 @@ def __call__(self): if dry_run: raise DryRunExit() - c = git.commit(m) + signoff: bool = self.arguments.get("signoff") + + if signoff: + c = git.commit(m, "-s") + else: + c = git.commit(m) if c.return_code != 0: out.error(c.err) diff --git a/tests/commands/test_commit_command.py b/tests/commands/test_commit_command.py index 7d56f08752..8544833c8f 100644 --- a/tests/commands/test_commit_command.py +++ b/tests/commands/test_commit_command.py @@ -107,6 +107,26 @@ def test_commit_command_with_dry_run_option(config, mocker): commit_cmd() +@pytest.mark.usefixtures("staging_is_clean") +def test_commit_command_with_signoff_option(config, mocker): + prompt_mock = mocker.patch("questionary.prompt") + prompt_mock.return_value = { + "prefix": "feat", + "subject": "user created", + "scope": "", + "is_breaking_change": False, + "body": "", + "footer": "", + } + + commit_mock = mocker.patch("commitizen.git.commit") + commit_mock.return_value = cmd.Command("success", "", "", "", 0) + success_mock = mocker.patch("commitizen.out.success") + + commands.Commit(config, {"signoff": True})() + success_mock.assert_called_once() + + def test_commit_when_nothing_to_commit(config, mocker): is_staging_clean_mock = mocker.patch("commitizen.git.is_staging_clean") is_staging_clean_mock.return_value = True From 7d2c3c2323b6670552d79f0e49ab5fe4666fbce2 Mon Sep 17 00:00:00 2001 From: peter_wu <peter_wu@trendmicro.com> Date: Mon, 4 Oct 2021 11:04:30 +0800 Subject: [PATCH 411/427] build: bump packaging to 22 to allow 21.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c3a8a820cd..a0a119da14 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,7 @@ questionary = "^1.4.0" decli = "^0.5.2" colorama = "^0.4.1" termcolor = "^1.1" -packaging = ">=19,<21" +packaging = ">=19,<22" tomlkit = ">=0.5.3,<1.0.0" jinja2 = ">=2.10.3" pyyaml = ">=3.08" From 5e220401f510f394129b5d2f11c6a987229c92de Mon Sep 17 00:00:00 2001 From: Angelo Mantellini <manangel@cisco.com> Date: Wed, 6 Oct 2021 20:10:37 +0200 Subject: [PATCH 412/427] feat(cli.py): add shortcut for signoff command add -s shortcut for the --signoff command --- commitizen/cli.py | 2 +- docs/README.md | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/commitizen/cli.py b/commitizen/cli.py index 215d8faf82..d582a27a18 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -50,7 +50,7 @@ "help": "show output to stdout, no commit, no modified files", }, { - "name": "--signoff", + "name": ["-s", "--signoff"], "action": "store_true", "help": "Sign off the commit", }, diff --git a/docs/README.md b/docs/README.md index f8482f4a69..f7c3127a9e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -86,6 +86,20 @@ or the shortcut cz c ``` +#### Sign off the commit + +Run in the terminal + +```bash +cz commit --signoff +``` + +or the shortcut + +```bash +cz commit -s +``` + ### Integrating with Pre-commit Commitizen can lint your commit message for you with `cz check`. You can integrate this in your [pre-commit](https://pre-commit.com/) config with: From 5a764bf172d6431e6192678a58dd2b8f7ab8daf6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com> Date: Wed, 6 Oct 2021 18:36:38 +0000 Subject: [PATCH 413/427] =?UTF-8?q?bump:=20version=202.19.0=20=E2=86=92=20?= =?UTF-8?q?2.20.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 7 +++++++ commitizen/__version__.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42630e4043..ac409aef82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,11 @@ +## v2.20.0 (2021-10-06) + +### Feat + +- **cli.py**: add shortcut for signoff command +- add signoff parameter to commit command + ## v2.19.0 (2021-09-27) ### Feat diff --git a/commitizen/__version__.py b/commitizen/__version__.py index 326b86ff29..3ea83e0a69 100644 --- a/commitizen/__version__.py +++ b/commitizen/__version__.py @@ -1 +1 @@ -__version__ = "2.19.0" +__version__ = "2.20.0" diff --git a/pyproject.toml b/pyproject.toml index a0a119da14..d1d0e37a47 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [tool.commitizen] -version = "2.19.0" +version = "2.20.0" tag_format = "v$version" version_files = [ "pyproject.toml:version", @@ -29,7 +29,7 @@ exclude = ''' [tool.poetry] name = "commitizen" -version = "2.19.0" +version = "2.20.0" description = "Python commitizen client tool" authors = ["Santiago Fraire <santiwilly@gmail.com>"] license = "MIT" From 87281ff6c9b609fa27050c772c391ad475adaf2c Mon Sep 17 00:00:00 2001 From: bogay <pojay11523@gmail.com> Date: Sun, 26 Sep 2021 15:59:23 +0800 Subject: [PATCH 414/427] docs: move all FAQs to docs/faq.md So now we have a single place to view all the FAQs. --- docs/README.md | 16 ++-------------- docs/faq.md | 7 +++++++ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/docs/README.md b/docs/README.md index f7c3127a9e..2411d9f744 100644 --- a/docs/README.md +++ b/docs/README.md @@ -189,23 +189,11 @@ See [Third-Party Commitizen Templates](third-party-commitizen.md). ## FAQ -### Why are `revert` and `chore` valid types in the check pattern of cz conventional_commits but not types we can select? - -`revert` and `chore` are added to the "pattern" in `cz check` in order to prevent backward errors, but officially they are not part of conventional commits, we are using the latest [types from Angular](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#type) (they used to but were removed). -However, you can create a customized `cz` with those extra types. (See [Customization](https://commitizen-tools.github.io/commitizen/customization)) - -See more discussion in issue [#142](https://github.com/commitizen-tools/commitizen/issues/142) and [#36](https://github.com/commitizen-tools/commitizen/issues/36) - -### How to handle revert commits? - -```sh -git revert --no-commit <SHA> -git commit -m "revert: foo bar" -``` +See [FAQ - commitizen](https://commitizen-tools.github.io/commitizen/faq/). ## Contributing -See [Contributing](contributing.md) +See [Contributing](contributing.md). [conventional_commits]: https://www.conventionalcommits.org [semver]: https://semver.org/ diff --git a/docs/faq.md b/docs/faq.md index c0e22cefde..4267ecf782 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -73,3 +73,10 @@ If you are using conventional commits in your git history, then you could swap o Regarding the name, [cz-js][cz-js] came first, they used the word commitizen first. When this project was created originally, the creator read "be a good commitizen", and thought it was just a cool word that made sense, and this would be a package that helps you be a good "commit citizen". [cz-js]: https://github.com/commitizen/cz-cli + +### How to handle revert commits? + +```sh +git revert --no-commit <SHA> +git commit -m "revert: foo bar" +``` From 0949575b5f6d2b29dcc79afeae58a8bd7f71616b Mon Sep 17 00:00:00 2001 From: bogay <pojay11523@gmail.com> Date: Sun, 26 Sep 2021 16:15:21 +0800 Subject: [PATCH 415/427] docs(faq): add WinError 995 description to FAQ --- docs/faq.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/faq.md b/docs/faq.md index 4267ecf782..8b4914f1c5 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -74,9 +74,15 @@ Regarding the name, [cz-js][cz-js] came first, they used the word commitizen fir [cz-js]: https://github.com/commitizen/cz-cli -### How to handle revert commits? +## How to handle revert commits? ```sh git revert --no-commit <SHA> git commit -m "revert: foo bar" ``` + +## I got `Exception [WinError 995] The I/O operation ...` error + +This error is cause by a python bug on windows and it should be fixed in some newer version. (e.g. 3.8.7) So if you encounter this error. Upgrade python version may solve this. + +More discussion can be found in issue [#318](https://github.com/commitizen-tools/commitizen/issues/318). From dd8e75ae0f84c837cfd2b17e0eca03961152a5ab Mon Sep 17 00:00:00 2001 From: bogay <pojay11523@gmail.com> Date: Mon, 27 Sep 2021 00:27:21 +0800 Subject: [PATCH 416/427] docs(faq): reword FAQ about WinError 995 Provide the accurate versions that should solve this issue. --- docs/faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/faq.md b/docs/faq.md index 8b4914f1c5..dac83b229f 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -83,6 +83,6 @@ git commit -m "revert: foo bar" ## I got `Exception [WinError 995] The I/O operation ...` error -This error is cause by a python bug on windows and it should be fixed in some newer version. (e.g. 3.8.7) So if you encounter this error. Upgrade python version may solve this. +This error was caused by a Python bug on Windows. It's been fixed by [this PR](https://github.com/python/cpython/pull/22017), and according to Python's changelog, [3.8.6rc1](https://docs.python.org/3.8/whatsnew/changelog.html#python-3-8-6-release-candidate-1) and [3.9.0rc2](https://docs.python.org/3.9/whatsnew/changelog.html#python-3-9-0-release-candidate-2) should be the accurate versions first contain this fix. In conclusion, upgrade your Python version might solve this issue. More discussion can be found in issue [#318](https://github.com/commitizen-tools/commitizen/issues/318). From 9e6ac64a49b36e5bb7fab91c3d82f163d9edf467 Mon Sep 17 00:00:00 2001 From: bogay <pojay11523@gmail.com> Date: Tue, 28 Sep 2021 16:33:07 +0800 Subject: [PATCH 417/427] docs: replace htperlinks' URL with filename According to mkdoc documentation, link to another page in the same documentation can directly use file path. mkdoc documentation: https://www.mkdocs.org/user-guide/writing-your-docs/#linking-to-pages --- docs/README.md | 4 ++-- docs/config.md | 10 +++++----- docs/customization.md | 4 ++-- docs/faq.md | 2 +- docs/tutorials/gitlab_ci.md | 2 +- docs/tutorials/writing_commits.md | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/README.md b/docs/README.md index 2411d9f744..d85c54d553 100644 --- a/docs/README.md +++ b/docs/README.md @@ -120,7 +120,7 @@ After the configuration is added, you'll need to run pre-commit install --hook-type commit-msg ``` -Read more about the `check` command [here](https://commitizen-tools.github.io/commitizen/check/). +Read more about the `check` command [here](check.md). ### Help @@ -189,7 +189,7 @@ See [Third-Party Commitizen Templates](third-party-commitizen.md). ## FAQ -See [FAQ - commitizen](https://commitizen-tools.github.io/commitizen/faq/). +See [FAQ](faq.md). ## Contributing diff --git a/docs/config.md b/docs/config.md index eee90e1dcc..d8af476e7f 100644 --- a/docs/config.md +++ b/docs/config.md @@ -134,9 +134,9 @@ commitizen: | `customize` | `dict` | `None` | **This is only supported when config through `toml`.** Custom rules for committing and bumping. [See more](customization) | | `use_shortcuts` | `bool` | `false` | If enabled, commitizen will show keyboard shortcuts when selecting from a list. Define a `key` for each of your choices to set the key. [See more](shortcuts) | -[version_files]: https://commitizen-tools.github.io/commitizen/bump/#version_files -[tag_format]: https://commitizen-tools.github.io/commitizen/bump/#tag_format -[bump_message]: https://commitizen-tools.github.io/commitizen/bump/#bump_message +[version_files]: bump.md#version_files +[tag_format]: bump.md#tag_format +[bump_message]: bump.md#bump_message [additional-features]: https://github.com/tmbo/questionary#additional-features -[customization]: https://commitizen-tools.github.io/commitizen/customization/ -[shortcuts]: https://commitizen-tools.github.io/commitizen/customization/#shortcut-keys +[customization]: customization.md +[shortcuts]: customization.md#shortcut-keys diff --git a/docs/customization.md b/docs/customization.md index b96c459e41..74ac0707b6 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -167,10 +167,10 @@ commitizen: #### Shortcut keys -When the [`use_shortcuts`](https://commitizen-tools.github.io/commitizen/config/#settings) config option is enabled, commitizen can show and use keyboard shortcuts to select items from lists directly. +When the [`use_shortcuts`](config.md#settings) config option is enabled, commitizen can show and use keyboard shortcuts to select items from lists directly. For example, when using the `cz_conventional_commits` commitizen template, shortcut keys are shown when selecting the commit type. Unless otherwise defined, keyboard shortcuts will be numbered automatically. To specify keyboard shortcuts for your custom choices, provide the shortcut using the `key` parameter in dictionary form for each choice you would like to customize. - + ## 2. Customize through customizing a class The basic steps are: diff --git a/docs/faq.md b/docs/faq.md index dac83b229f..7e1450e33c 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -30,7 +30,7 @@ version_files = [ ## Why are `revert` and `chore` valid types in the check pattern of cz conventional_commits but not types we can select? `revert` and `chore` are added to the "pattern" in `cz check` in order to prevent backward errors, but officially they are not part of conventional commits, we are using the latest [types from Angular](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#type) (they used to but were removed). -However, you can create a customized `cz` with those extra types. (See [Customization](https://commitizen-tools.github.io/commitizen/customization/) +However, you can create a customized `cz` with those extra types. (See [Customization](customization.md) See more discussion in issue [#142](https://github.com/commitizen-tools/commitizen/issues/142) and [#36](https://github.com/commitizen-tools/commitizen/issues/36) diff --git a/docs/tutorials/gitlab_ci.md b/docs/tutorials/gitlab_ci.md index 9be03d1966..2859db7318 100644 --- a/docs/tutorials/gitlab_ci.md +++ b/docs/tutorials/gitlab_ci.md @@ -10,7 +10,7 @@ _Goal_: Bump a new version every time that a change occurs on the `master` branc 2. A developer creates a merge request (MR) against `master` branch 3. When the `MR` is merged into master, the 2 stages of the CI are executed 4. For simplification, we store the software version in a file called `VERSION`. You can use any file that you want as `commitizen` supports it. -5. The commit message executed automatically by the `CI` must include `[skip-ci]` in the message; otherwise, the process will generate a loop. You can define the message structure in [commitizen](https://commitizen-tools.github.io/commitizen/bump/) as well. +5. The commit message executed automatically by the `CI` must include `[skip-ci]` in the message; otherwise, the process will generate a loop. You can define the message structure in [commitizen](../bump.md) as well. ### Gitlab Configuration diff --git a/docs/tutorials/writing_commits.md b/docs/tutorials/writing_commits.md index 4cf377a8c1..4bc20f9773 100644 --- a/docs/tutorials/writing_commits.md +++ b/docs/tutorials/writing_commits.md @@ -38,5 +38,5 @@ understand what happened. | `fix(commands): bump error when no user provided` | `fix: stuff` | | `feat: add new commit command` | `feat: commit command introduced` | -[customization]: https://commitizen-tools.github.io/commitizen/customization/ +[customization]: customization.md [conventional_commits]: https://www.conventionalcommits.org From ed1148857b9c98f15b0738d0ad7637a93ad95e47 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Wed, 6 Oct 2021 22:56:35 +0800 Subject: [PATCH 418/427] style(github-template): remove trailing space --- .github/ISSUE_TEMPLATE/bug_report.md | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 73d632fd13..944a95723e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -42,4 +42,3 @@ Add output of the following command to include the following ```bash cz version --report ``` - From e9eb2623341bb7e47c1050fd032e0015d150880d Mon Sep 17 00:00:00 2001 From: bogay <pojay11523@gmail.com> Date: Thu, 7 Oct 2021 15:24:29 +0800 Subject: [PATCH 419/427] docs: fix missing link --- docs/tutorials/writing_commits.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/writing_commits.md b/docs/tutorials/writing_commits.md index 4bc20f9773..dbeee66db8 100644 --- a/docs/tutorials/writing_commits.md +++ b/docs/tutorials/writing_commits.md @@ -38,5 +38,5 @@ understand what happened. | `fix(commands): bump error when no user provided` | `fix: stuff` | | `feat: add new commit command` | `feat: commit command introduced` | -[customization]: customization.md +[customization]: ../customization.md [conventional_commits]: https://www.conventionalcommits.org From 7e8d795ed459b6ee363f7eb8e608f8d9c94bb46b Mon Sep 17 00:00:00 2001 From: bogay <pojay11523@gmail.com> Date: Thu, 7 Oct 2021 15:28:43 +0800 Subject: [PATCH 420/427] docs(contributing): add instruction to verify documentation change --- docs/contributing.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/contributing.md b/docs/contributing.md index b106edc73c..0dcd5c5bff 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -18,6 +18,7 @@ If you're a first-time contributor, you can check the issues with [good first is 7. Use [commitizen](https://github.com/commitizen-tools/commitizen) to do git commit. We follow [conventional commmits][conventional-commmits] 8. Run `./scripts/format` and `./scripts/test` to ensure you follow the coding style and the tests pass. 9. Update `README.md`. Do **not** update the `CHANGELOG.md`, it will be automatically created after merging to `master`. -10. Send a [pull request](https://github.com/commitizen-tools/commitizen/pulls) 🙏 +10. If your changes are about documentation. Run `poetry run mkdocs serve` to serve documentation locally and check whether there is any warning or error. +11. Send a [pull request](https://github.com/commitizen-tools/commitizen/pulls) 🙏 [conventional-commmits]: https://www.conventionalcommits.org/ From 0d407d74943b17ac2f76ec2d3b010917326b935a Mon Sep 17 00:00:00 2001 From: bogay <pojay11523@gmail.com> Date: Thu, 7 Oct 2021 15:32:59 +0800 Subject: [PATCH 421/427] docs(readme): remove sections only contains one link --- docs/README.md | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/docs/README.md b/docs/README.md index d85c54d553..3bb2db5588 100644 --- a/docs/README.md +++ b/docs/README.md @@ -183,18 +183,6 @@ eval "$(register-python-argcomplete cz)" For further information on activation, please visit the [argcomplete website](https://kislyuk.github.io/argcomplete/). -## Third-Party Commitizen Templates - -See [Third-Party Commitizen Templates](third-party-commitizen.md). - -## FAQ - -See [FAQ](faq.md). - -## Contributing - -See [Contributing](contributing.md). - [conventional_commits]: https://www.conventionalcommits.org [semver]: https://semver.org/ [keepchangelog]: https://keepachangelog.com/ From 1ea05accd5c655e15eea9d4be54710ef6832aabb Mon Sep 17 00:00:00 2001 From: bogay <pojay11523@gmail.com> Date: Thu, 7 Oct 2021 16:08:26 +0800 Subject: [PATCH 422/427] docs(config): fix broken links These reference-style links should in `[link][id]` format instead of `[link](id)`. --- docs/config.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/config.md b/docs/config.md index d8af476e7f..342219fef2 100644 --- a/docs/config.md +++ b/docs/config.md @@ -126,13 +126,13 @@ commitizen: | ---------------- | ------ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | `str` | `"cz_conventional_commits"` | Name of the committing rules to use | | `version` | `str` | `None` | Current version. Example: "0.1.2" | -| `version_files` | `list` | `[ ]` | Files were the version will be updated. A pattern to match a line, can also be specified, separated by `:` [See more](version_files) | -| `tag_format` | `str` | `None` | Format for the git tag, useful for old projects, that use a convention like `"v1.2.1"`. [See more](tag_format) | -| `bump_message` | `str` | `None` | Create custom commit message, useful to skip ci. [See more](bump_message) | +| `version_files` | `list` | `[ ]` | Files were the version will be updated. A pattern to match a line, can also be specified, separated by `:` [See more][version_files] | +| `tag_format` | `str` | `None` | Format for the git tag, useful for old projects, that use a convention like `"v1.2.1"`. [See more][tag_format] | +| `bump_message` | `str` | `None` | Create custom commit message, useful to skip ci. [See more][bump_message] | | `changelog_file` | `str` | `CHANGELOG.md` | filename of exported changelog | -| `style` | `list` | see above | Style for the prompts (It will merge this value with default style.) [See More (Styling your prompts with your favorite colors)](additional-features) | -| `customize` | `dict` | `None` | **This is only supported when config through `toml`.** Custom rules for committing and bumping. [See more](customization) | -| `use_shortcuts` | `bool` | `false` | If enabled, commitizen will show keyboard shortcuts when selecting from a list. Define a `key` for each of your choices to set the key. [See more](shortcuts) | +| `style` | `list` | see above | Style for the prompts (It will merge this value with default style.) [See More (Styling your prompts with your favorite colors)][additional-features] | +| `customize` | `dict` | `None` | **This is only supported when config through `toml`.** Custom rules for committing and bumping. [See more][customization] | +| `use_shortcuts` | `bool` | `false` | If enabled, commitizen will show keyboard shortcuts when selecting from a list. Define a `key` for each of your choices to set the key. [See more][shortcuts] | [version_files]: bump.md#version_files [tag_format]: bump.md#tag_format From 71aabe8c675a84cff0587a2f620a85dbecc6f82f Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sat, 9 Oct 2021 15:03:19 +0800 Subject: [PATCH 423/427] ci(github-actions): set force to true for Homebrew bump formula --- .github/workflows/homebrewpublish.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/homebrewpublish.yaml b/.github/workflows/homebrewpublish.yaml index 817d881794..2ff28078b0 100644 --- a/.github/workflows/homebrewpublish.yaml +++ b/.github/workflows/homebrewpublish.yaml @@ -29,3 +29,4 @@ jobs: token: ${{secrets.PERSONAL_ACCESS_TOKEN}} formula: commitizen tag: v${{ env.project_version }} + force: true From d7332d73627cf8265e0ad45cee1d16069d936191 Mon Sep 17 00:00:00 2001 From: saygox <ito.saygo@gmail.com> Date: Fri, 14 Aug 2020 08:52:47 +0900 Subject: [PATCH 424/427] feat(commands/commit): apply prepare-commit-msg hook add --commit-msg-file argument --- .pre-commit-hooks.yaml | 8 ++++++ commitizen/cli.py | 8 ++++++ commitizen/commands/commit.py | 40 ++++++++++++++++++++++++++ docs/README.md | 4 ++- tests/commands/test_commit_command.py | 41 ++++++++++++++++++++++++++- 5 files changed, 99 insertions(+), 2 deletions(-) diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index 956f15250e..6c45efbb0f 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -6,3 +6,11 @@ language_version: python3 require_serial: true minimum_pre_commit_version: "0.15.4" +- id: commitizen-prepare-commit-msg + name: commitizen prepare commit msg + description: "prepare commit message" + entry: cz commit --commit-msg-file + language: python + language_version: python3 + require_serial: true + minimum_pre_commit_version: "0.15.4" diff --git a/commitizen/cli.py b/commitizen/cli.py index d582a27a18..19a465d7ab 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -54,6 +54,14 @@ "action": "store_true", "help": "Sign off the commit", }, + { + "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/commit.py b/commitizen/commands/commit.py index a4c0301732..a5db43c677 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -1,5 +1,6 @@ import contextlib import os +import sys import tempfile import questionary @@ -18,6 +19,21 @@ ) +class WrapStdin: + def __init__(self): + fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY) + tty = open(fd, "wb+", buffering=0) + self.tty = tty + + def __getattr__(self, key): + if key == "encoding": + return "UTF-8" + return getattr(self.tty, key) + + def __del__(self): + self.tty.close() + + class Commit: """Show prompt for the user to create a guided commit.""" @@ -63,6 +79,15 @@ def prompt_commit_questions(self) -> str: def __call__(self): dry_run: bool = self.arguments.get("dry_run") + commit_msg_file: str = self.arguments.get("commit_msg_file") + if commit_msg_file: + old_stdin = sys.stdin + old_stdout = sys.stdout + old_stderr = sys.stderr + sys.stdin = WrapStdin() + sys.stdout = open("/dev/tty", "w") + sys.stderr = open("/dev/tty", "w") + if git.is_staging_clean() and not dry_run: raise NothingToCommitError("No files added to staging!") @@ -78,6 +103,21 @@ def __call__(self): if dry_run: raise DryRunExit() + if commit_msg_file: + sys.stdin.close() + sys.stdout.close() + sys.stderr.close() + sys.stdin = old_stdin + sys.stdout = old_stdout + sys.stderr = old_stderr + defaultmesaage = "" + with open(commit_msg_file) as f: + defaultmesaage = f.read() + with open(commit_msg_file, "w") as f: + f.write(m) + f.write(defaultmesaage) + out.success("Commit message is successful!") + return signoff: bool = self.arguments.get("signoff") if signoff: diff --git a/docs/README.md b/docs/README.md index 3bb2db5588..6791891d22 100644 --- a/docs/README.md +++ b/docs/README.md @@ -101,7 +101,7 @@ cz commit -s ``` ### Integrating with Pre-commit -Commitizen can lint your commit message for you with `cz check`. +Commitizen can lint your commit message for you with `cz check` and `cz commit`. You can integrate this in your [pre-commit](https://pre-commit.com/) config with: ```yaml @@ -112,6 +112,8 @@ repos: hooks: - id: commitizen stages: [commit-msg] + - id: commitizen-prepare-commit-msg + stages: [prepare-commit-msg] ``` After the configuration is added, you'll need to run diff --git a/tests/commands/test_commit_command.py b/tests/commands/test_commit_command.py index 8544833c8f..a2b22b48bf 100644 --- a/tests/commands/test_commit_command.py +++ b/tests/commands/test_commit_command.py @@ -1,8 +1,9 @@ import os +import sys import pytest -from commitizen import cmd, commands +from commitizen import cli, cmd, commands from commitizen.cz.exceptions import CzException from commitizen.exceptions import ( CommitError, @@ -178,3 +179,41 @@ def test_commit_in_non_git_project(tmpdir, config): with tmpdir.as_cwd(): with pytest.raises(NotAGitProjectError): commands.Commit(config, {}) + + +def test_commit_from_pre_commit_msg_hook(config, mocker, capsys): + testargs = ["cz", "commit", "--commit-msg-file", "some_file"] + mocker.patch.object(sys, "argv", testargs) + + prompt_mock = mocker.patch("questionary.prompt") + prompt_mock.return_value = { + "prefix": "feat", + "subject": "user created", + "scope": "", + "is_breaking_change": False, + "body": "", + "footer": "", + } + + commit_mock = mocker.patch("commitizen.git.commit") + mocker.patch("commitizen.commands.commit.WrapStdin") + mocker.patch("os.open") + reader_mock = mocker.mock_open(read_data="\n\n#test\n") + mocker.patch("builtins.open", reader_mock, create=True) + + cli.main() + + out, _ = capsys.readouterr() + assert "Commit message is successful!" in out + commit_mock.assert_not_called() + + +def test_WrapStdin(mocker): + mocker.patch("os.open") + reader_mock = mocker.mock_open(read_data="data") + mocker.patch("builtins.open", reader_mock, create=True) + + wrap_stdin = commands.commit.WrapStdin() + + assert wrap_stdin.encoding == "UTF-8" + assert wrap_stdin.read() == "data" From 6a665d9a8b563f7f48b00bf40d45b2a26cd2d548 Mon Sep 17 00:00:00 2001 From: saygox <ito.saygo@gmail.com> Date: Fri, 14 Aug 2020 18:39:50 +0900 Subject: [PATCH 425/427] test(commands/commit): set staging_is_clean to pre_commit_msg_hook for pass the python-check (3.8) --- tests/commands/test_commit_command.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/commands/test_commit_command.py b/tests/commands/test_commit_command.py index a2b22b48bf..1387828d7b 100644 --- a/tests/commands/test_commit_command.py +++ b/tests/commands/test_commit_command.py @@ -181,6 +181,7 @@ def test_commit_in_non_git_project(tmpdir, config): commands.Commit(config, {}) +@pytest.mark.usefixtures("staging_is_clean") def test_commit_from_pre_commit_msg_hook(config, mocker, capsys): testargs = ["cz", "commit", "--commit-msg-file", "some_file"] mocker.patch.object(sys, "argv", testargs) From 906b83c29a7447d9a73119628ecf4004c62fdef1 Mon Sep 17 00:00:00 2001 From: saygox <ito.saygo@gmail.com> Date: Sat, 6 Nov 2021 22:40:30 +0900 Subject: [PATCH 426/427] feat(commands/commit): apply prepare-commit-msg hook for Mac --- commitizen/commands/commit.py | 47 ++++++++++++++++++++++----- tests/commands/test_commit_command.py | 34 ++++++++++++++++--- 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index a5db43c677..d0255331eb 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -1,8 +1,12 @@ import contextlib import os +import selectors import sys import tempfile +from asyncio import set_event_loop_policy, get_event_loop_policy, DefaultEventLoopPolicy +from io import IOBase + import questionary from commitizen import factory, git, out @@ -19,14 +23,30 @@ ) -class WrapStdin: - def __init__(self): - fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY) - tty = open(fd, "wb+", buffering=0) +class CZEventLoopPolicy(DefaultEventLoopPolicy): + def get_event_loop(self): + self.set_event_loop(self._loop_factory(selectors.SelectSelector())) + return self._local._loop + +class WrapStdx: + def __init__(self, stdx:IOBase): + self._fileno = stdx.fileno() + if sys.platform == 'linux': + if self._fileno == 0: + fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY) + tty = open(fd, "wb+", buffering=0) + else: + tty = open("/dev/tty", "w") + else: + fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY) + if self._fileno == 0: + tty = open(fd, "wb+", buffering=0) + else: + tty = open(fd, "rb+", buffering=0) self.tty = tty def __getattr__(self, key): - if key == "encoding": + if key == "encoding" and (sys.platform != 'linux' or self._fileno == 0) : return "UTF-8" return getattr(self.tty, key) @@ -84,9 +104,11 @@ def __call__(self): old_stdin = sys.stdin old_stdout = sys.stdout old_stderr = sys.stderr - sys.stdin = WrapStdin() - sys.stdout = open("/dev/tty", "w") - sys.stderr = open("/dev/tty", "w") + old_event_loop_policy=get_event_loop_policy() + set_event_loop_policy(CZEventLoopPolicy()) + sys.stdin = WrapStdx(sys.stdin) + sys.stdout = WrapStdx(sys.stdout) + sys.stderr = WrapStdx(sys.stderr) if git.is_staging_clean() and not dry_run: raise NothingToCommitError("No files added to staging!") @@ -107,6 +129,7 @@ def __call__(self): sys.stdin.close() sys.stdout.close() sys.stderr.close() + set_event_loop_policy(old_event_loop_policy) sys.stdin = old_stdin sys.stdout = old_stdout sys.stderr = old_stderr @@ -125,6 +148,14 @@ def __call__(self): else: c = git.commit(m) + signoff: bool = self.arguments.get("signoff") + + if signoff: + c = git.commit(m, "-s") + else: + c = git.commit(m) + + if c.return_code != 0: out.error(c.err) diff --git a/tests/commands/test_commit_command.py b/tests/commands/test_commit_command.py index 1387828d7b..25bd194ec5 100644 --- a/tests/commands/test_commit_command.py +++ b/tests/commands/test_commit_command.py @@ -197,7 +197,8 @@ def test_commit_from_pre_commit_msg_hook(config, mocker, capsys): } commit_mock = mocker.patch("commitizen.git.commit") - mocker.patch("commitizen.commands.commit.WrapStdin") + commit_mock.return_value = cmd.Command("success", "", "", "", 0) + mocker.patch("commitizen.commands.commit.WrapStdx") mocker.patch("os.open") reader_mock = mocker.mock_open(read_data="\n\n#test\n") mocker.patch("builtins.open", reader_mock, create=True) @@ -208,13 +209,38 @@ def test_commit_from_pre_commit_msg_hook(config, mocker, capsys): assert "Commit message is successful!" in out commit_mock.assert_not_called() - -def test_WrapStdin(mocker): +def test_WrapStdx(mocker): mocker.patch("os.open") reader_mock = mocker.mock_open(read_data="data") mocker.patch("builtins.open", reader_mock, create=True) - wrap_stdin = commands.commit.WrapStdin() + stdin_mock_fileno=mocker.patch.object(sys.stdin, 'fileno') + stdin_mock_fileno.return_value = 0 + wrap_stdin = commands.commit.WrapStdx(sys.stdin) assert wrap_stdin.encoding == "UTF-8" assert wrap_stdin.read() == "data" + + + writer_mock = mocker.mock_open(read_data="data") + mocker.patch("builtins.open", writer_mock, create=True) + stdout_mock_fileno=mocker.patch.object(sys.stdout, 'fileno') + stdout_mock_fileno.return_value = 1 + wrap_stout = commands.commit.WrapStdx(sys.stdout) + wrap_stout.write("data") + + writer_mock.assert_called_once_with("/dev/tty", 'w') + writer_mock().write.assert_called_once_with("data") + + + writer_mock = mocker.mock_open(read_data="data") + mocker.patch("builtins.open", writer_mock, create=True) + stderr_mock_fileno=mocker.patch.object(sys.stdout, 'fileno') + stderr_mock_fileno.return_value = 2 + wrap_sterr = commands.commit.WrapStdx(sys.stderr) + + + wrap_sterr.write("data") + + writer_mock.assert_called_once_with("/dev/tty", 'w') + writer_mock().write.assert_called_once_with("data") From 79d17dfe035d139a49f947f516a29870f5208610 Mon Sep 17 00:00:00 2001 From: Wei Lee <weilee.rx@gmail.com> Date: Sun, 7 Nov 2021 11:53:00 +0800 Subject: [PATCH 427/427] style: format code --- commitizen/commands/commit.py | 13 ++++++------- docs/auto_check.md | 3 +-- docs/check.md | 2 +- tests/commands/test_commit_command.py | 14 ++++++-------- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/commitizen/commands/commit.py b/commitizen/commands/commit.py index d0255331eb..1baad30b95 100644 --- a/commitizen/commands/commit.py +++ b/commitizen/commands/commit.py @@ -3,8 +3,7 @@ import selectors import sys import tempfile - -from asyncio import set_event_loop_policy, get_event_loop_policy, DefaultEventLoopPolicy +from asyncio import DefaultEventLoopPolicy, get_event_loop_policy, set_event_loop_policy from io import IOBase import questionary @@ -28,10 +27,11 @@ def get_event_loop(self): self.set_event_loop(self._loop_factory(selectors.SelectSelector())) return self._local._loop + class WrapStdx: - def __init__(self, stdx:IOBase): + def __init__(self, stdx: IOBase): self._fileno = stdx.fileno() - if sys.platform == 'linux': + if sys.platform == "linux": if self._fileno == 0: fd = os.open("/dev/tty", os.O_RDWR | os.O_NOCTTY) tty = open(fd, "wb+", buffering=0) @@ -46,7 +46,7 @@ def __init__(self, stdx:IOBase): self.tty = tty def __getattr__(self, key): - if key == "encoding" and (sys.platform != 'linux' or self._fileno == 0) : + if key == "encoding" and (sys.platform != "linux" or self._fileno == 0): return "UTF-8" return getattr(self.tty, key) @@ -104,7 +104,7 @@ def __call__(self): old_stdin = sys.stdin old_stdout = sys.stdout old_stderr = sys.stderr - old_event_loop_policy=get_event_loop_policy() + old_event_loop_policy = get_event_loop_policy() set_event_loop_policy(CZEventLoopPolicy()) sys.stdin = WrapStdx(sys.stdin) sys.stdout = WrapStdx(sys.stdout) @@ -155,7 +155,6 @@ def __call__(self): else: c = git.commit(m) - if c.return_code != 0: out.error(c.err) diff --git a/docs/auto_check.md b/docs/auto_check.md index 9d746dda50..755f1af8b7 100644 --- a/docs/auto_check.md +++ b/docs/auto_check.md @@ -1,7 +1,7 @@ # Automatically check message before commit ## About -To automatically check a commit message prior to committing, you can use a [git hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks). +To automatically check a commit message prior to committing, you can use a [git hook](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks). ## How to There are two common methods for installing the hook: @@ -62,4 +62,3 @@ Each time you create a commit, automatically, this hook will analyze it. If the commit message is invalid, it'll be rejected. The commit should follow the given committing rules; otherwise, it won't be accepted. - diff --git a/docs/check.md b/docs/check.md index 9150f608de..d1e1b72056 100644 --- a/docs/check.md +++ b/docs/check.md @@ -2,7 +2,7 @@ ## About This feature checks whether the commit message follows the given committing rules. -If you want to setup an automatic check before every git commit, please refer to +If you want to setup an automatic check before every git commit, please refer to [Automatically check message before commit](auto_check.md). ## Usage diff --git a/tests/commands/test_commit_command.py b/tests/commands/test_commit_command.py index 25bd194ec5..0735146b58 100644 --- a/tests/commands/test_commit_command.py +++ b/tests/commands/test_commit_command.py @@ -209,38 +209,36 @@ def test_commit_from_pre_commit_msg_hook(config, mocker, capsys): assert "Commit message is successful!" in out commit_mock.assert_not_called() + def test_WrapStdx(mocker): mocker.patch("os.open") reader_mock = mocker.mock_open(read_data="data") mocker.patch("builtins.open", reader_mock, create=True) - stdin_mock_fileno=mocker.patch.object(sys.stdin, 'fileno') + stdin_mock_fileno = mocker.patch.object(sys.stdin, "fileno") stdin_mock_fileno.return_value = 0 wrap_stdin = commands.commit.WrapStdx(sys.stdin) assert wrap_stdin.encoding == "UTF-8" assert wrap_stdin.read() == "data" - writer_mock = mocker.mock_open(read_data="data") mocker.patch("builtins.open", writer_mock, create=True) - stdout_mock_fileno=mocker.patch.object(sys.stdout, 'fileno') + stdout_mock_fileno = mocker.patch.object(sys.stdout, "fileno") stdout_mock_fileno.return_value = 1 wrap_stout = commands.commit.WrapStdx(sys.stdout) wrap_stout.write("data") - writer_mock.assert_called_once_with("/dev/tty", 'w') + writer_mock.assert_called_once_with("/dev/tty", "w") writer_mock().write.assert_called_once_with("data") - writer_mock = mocker.mock_open(read_data="data") mocker.patch("builtins.open", writer_mock, create=True) - stderr_mock_fileno=mocker.patch.object(sys.stdout, 'fileno') + stderr_mock_fileno = mocker.patch.object(sys.stdout, "fileno") stderr_mock_fileno.return_value = 2 wrap_sterr = commands.commit.WrapStdx(sys.stderr) - wrap_sterr.write("data") - writer_mock.assert_called_once_with("/dev/tty", 'w') + writer_mock.assert_called_once_with("/dev/tty", "w") writer_mock().write.assert_called_once_with("data")