Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ConventionalCommitsCz): allow to override defaults from config #546

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 25 additions & 37 deletions commitizen/cz/base.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,14 @@
from abc import ABCMeta, abstractmethod
from typing import Callable, Dict, List, Optional, Tuple
from typing import Callable, Dict, List, Optional

from prompt_toolkit.styles import Style, merge_styles
from prompt_toolkit.styles import Style

from commitizen import git
from commitizen import defaults, git
from commitizen.config.base_config import BaseConfig
from commitizen.defaults import Questions


class BaseCommitizen(metaclass=ABCMeta):
bump_pattern: Optional[str] = None
bump_map: Optional[Dict[str, str]] = None
default_style_config: List[Tuple[str, str]] = [
("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 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".*"
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[
Callable[[Dict, git.GitCommit], Dict]
Expand All @@ -42,8 +19,28 @@ class BaseCommitizen(metaclass=ABCMeta):

def __init__(self, config: BaseConfig):
self.config = config
if not self.config.settings.get("style"):
self.config.settings.update({"style": BaseCommitizen.default_style_config})
self.style = Style(self.config.settings.get("style", defaults.style))
self.bump_pattern: Optional[str] = self.config.settings.get(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say the defaults.bump_pattern is something only for conventional commit that I want to move out from default and move it to conventional commit. Thus, I'd like to keep the default value of this as None

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This behavior should be applied to all the following default values which did not exist in BaseCommitizen

"bump_pattern", defaults.bump_pattern
)
self.bump_map: Optional[Dict[str, str]] = self.config.settings.get(
"bump_map", defaults.bump_map
)
self.change_type_order: Optional[List[str]] = self.config.settings.get(
"change_type_order", defaults.change_type_order
)
self.change_type_map: Optional[Dict[str, str]] = self.config.settings.get(
"change_type_map", defaults.change_type_map
)
self.commit_parser: Optional[str] = self.config.settings.get(
"commit_parser", defaults.commit_parser
)
self.changelog_pattern: Optional[str] = self.config.settings.get(
"changelog_pattern", defaults.changelog_pattern
)
self.version_parser = self.config.settings.get(
"version_parser", defaults.version_parser
)

@abstractmethod
def questions(self) -> Questions:
Expand All @@ -53,15 +50,6 @@ def questions(self) -> Questions:
def message(self, answers: dict) -> str:
"""Format your git message."""

@property
def style(self):
return merge_styles(
[
Style(BaseCommitizen.default_style_config),
Style(self.config.settings["style"]),
]
)

def example(self) -> Optional[str]:
"""Example of the commit message."""
raise NotImplementedError("Not Implemented yet")
Expand Down
55 changes: 31 additions & 24 deletions commitizen/cz/conventional_commits/conventional_commits.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import os
import re

from commitizen import defaults
try:
from jinja2 import Template
except ImportError:
from string import Template # type: ignore

from commitizen.cz.base import BaseCommitizen
from commitizen.cz.utils import multiple_line_breaker, required_validator
from commitizen.defaults import Questions
Expand All @@ -28,18 +32,6 @@ def parse_subject(text):


class ConventionalCommitsCz(BaseCommitizen):
bump_pattern = defaults.bump_pattern
bump_map = defaults.bump_map
commit_parser = defaults.commit_parser
version_parser = defaults.version_parser
change_type_map = {
"feat": "Feat",
"fix": "Fix",
"refactor": "Refactor",
"perf": "Perf",
}
changelog_pattern = defaults.bump_pattern

def questions(self) -> Questions:
questions: Questions = [
{
Expand Down Expand Up @@ -148,9 +140,20 @@ def questions(self) -> Questions:
),
},
]
return questions

return self.config.settings.get("questions", questions)

def message(self, answers: dict) -> str:
custom_message = self.config.settings.get("message_template")
if custom_message:
message_template = Template(
str(self.config.settings.get("message_template", ""))
)
if getattr(Template, "substitute", None):
return message_template.substitute(**answers) # type: ignore
else:
return message_template.render(**answers)

prefix = answers["prefix"]
scope = answers["scope"]
subject = answers["subject"]
Expand All @@ -172,32 +175,36 @@ def message(self, answers: dict) -> str:
return message

def example(self) -> str:
return (
"fix: correct minor typos in code\n"
"\n"
"see the issue for details on the typos fixed\n"
"\n"
"closes issue #12"
return str(
self.config.settings.get(
"example",
"fix: correct minor typos in code\n"
"\n"
"see the issue for details on the typos fixed\n"
"\n"
"closes issue #12",
)
)

def schema(self) -> str:
return (
return self.config.settings.get(
"schema",
"<type>(<scope>): <subject>\n"
"<BLANK LINE>\n"
"<body>\n"
"<BLANK LINE>\n"
"(BREAKING CHANGE: )<footer>"
"(BREAKING CHANGE: )<footer>",
Lee-W marked this conversation as resolved.
Show resolved Hide resolved
)

def schema_pattern(self) -> str:
PATTERN = (
r"(?s)" # To explictly make . match new line
r"(?s)" # To explicitly make . match new line
r"(build|ci|docs|feat|fix|perf|refactor|style|test|chore|revert|bump)" # type
r"(\(\S+\))?!?:" # scope
r"( [^\n\r]+)" # subject
r"((\n\n.*)|(\s*))?$"
)
return PATTERN
return self.config.settings.get("schema_pattern", PATTERN)

def info(self) -> str:
dir_path = os.path.dirname(os.path.realpath(__file__))
Expand Down
8 changes: 8 additions & 0 deletions commitizen/cz/jira/jira.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import os

from commitizen.config.base_config import BaseConfig
from commitizen.cz.base import BaseCommitizen
from commitizen.defaults import Questions

__all__ = ["JiraSmartCz"]


class JiraSmartCz(BaseCommitizen):
def __init__(self, config: BaseConfig):
super().__init__(config)
self.bump_map = None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the values here is the ideal default values in BaseCommitizen and we should move the defaults to ConventionalCommitsCz

self.bump_pattern = None
self.commit_parser = r"(?P<message>.*)"
self.changelog_pattern = r".*"

def questions(self) -> Questions:
questions = [
{
Expand Down
36 changes: 34 additions & 2 deletions commitizen/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,23 @@ class Settings(TypedDict, total=False):
version_files: List[str]
tag_format: Optional[str]
bump_message: Optional[str]
bump_pattern: Optional[str]
bump_map: Optional[Dict[str, str]]
allow_abort: bool
changelog_file: str
changelog_incremental: bool
changelog_start_rev: Optional[str]
changelog_pattern: Optional[str]
update_changelog_on_bump: bool
use_shortcuts: bool
style: Optional[List[Tuple[str, str]]]
style: List[Tuple[str, str]]
customize: CzSettings
change_type_order: Optional[List[str]]
change_type_map: Optional[Dict[str, str]]
commit_parser: Optional[str]
schema: str
schema_pattern: str
questions: Questions


name: str = "cz_conventional_commits"
Expand Down Expand Up @@ -80,8 +89,31 @@ class Settings(TypedDict, total=False):
(r"^perf", PATCH),
)
)
change_type_order = ["BREAKING CHANGE", "Feat", "Fix", "Refactor", "Perf"]
change_type_order: Optional[List[str]] = None

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-]+)?(\w+)?)"

change_type_map = {
"feat": "Feat",
"fix": "Fix",
"refactor": "Refactor",
"perf": "Perf",
}

changelog_pattern = bump_pattern

style: List[Tuple[str, str]] = [
("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"),
]
6 changes: 4 additions & 2 deletions tests/test_bump_find_increment.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import pytest

from commitizen import bump
from commitizen.config.base_config import BaseConfig
from commitizen.cz import ConventionalCommitsCz
from commitizen.git import GitCommit

Expand Down Expand Up @@ -72,11 +73,12 @@
),
)
def test_find_increment(messages, expected_type):
cz = ConventionalCommitsCz(BaseConfig())
commits = [GitCommit(rev="test", title=message) for message in messages]
increment_type = bump.find_increment(
commits,
regex=ConventionalCommitsCz.bump_pattern,
increments_map=ConventionalCommitsCz.bump_map,
regex=cz.bump_pattern,
increments_map=cz.bump_map,
)
assert increment_type == expected_type

Expand Down
26 changes: 16 additions & 10 deletions tests/test_changelog.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pytest

from commitizen import changelog, defaults, git
from commitizen.config.base_config import BaseConfig
from commitizen.cz.conventional_commits.conventional_commits import (
ConventionalCommitsCz,
)
Expand Down Expand Up @@ -844,8 +845,9 @@ def test_order_changelog_tree_raises():


def test_render_changelog(gitcommits, tags, changelog_content):
parser = ConventionalCommitsCz.commit_parser
changelog_pattern = ConventionalCommitsCz.bump_pattern
cz = ConventionalCommitsCz(BaseConfig())
parser = cz.commit_parser
changelog_pattern = cz.bump_pattern
tree = changelog.generate_tree_from_commits(
gitcommits, tags, parser, changelog_pattern
)
Expand All @@ -854,9 +856,10 @@ def test_render_changelog(gitcommits, tags, changelog_content):


def test_render_changelog_unreleased(gitcommits):
cz = ConventionalCommitsCz(BaseConfig())
some_commits = gitcommits[:7]
parser = ConventionalCommitsCz.commit_parser
changelog_pattern = ConventionalCommitsCz.bump_pattern
parser = cz.commit_parser
changelog_pattern = cz.bump_pattern
tree = changelog.generate_tree_from_commits(
some_commits, [], parser, changelog_pattern
)
Expand All @@ -869,9 +872,10 @@ def test_render_changelog_tag_and_unreleased(gitcommits, tags):
single_tag = [
tag for tag in tags if tag.rev == "56c8a8da84e42b526bcbe130bd194306f7c7e813"
]
cz = ConventionalCommitsCz(BaseConfig())

parser = ConventionalCommitsCz.commit_parser
changelog_pattern = ConventionalCommitsCz.bump_pattern
parser = cz.commit_parser
changelog_pattern = cz.bump_pattern
tree = changelog.generate_tree_from_commits(
some_commits, single_tag, parser, changelog_pattern
)
Expand All @@ -882,10 +886,11 @@ def test_render_changelog_tag_and_unreleased(gitcommits, tags):


def test_render_changelog_with_change_type(gitcommits, tags):
cz = ConventionalCommitsCz(BaseConfig())
new_title = ":some-emoji: feature"
change_type_map = {"feat": new_title}
parser = ConventionalCommitsCz.commit_parser
changelog_pattern = ConventionalCommitsCz.bump_pattern
parser = cz.commit_parser
changelog_pattern = cz.bump_pattern
tree = changelog.generate_tree_from_commits(
gitcommits, tags, parser, changelog_pattern, change_type_map=change_type_map
)
Expand All @@ -900,8 +905,9 @@ def changelog_message_builder_hook(message: dict, commit: git.GitCommit) -> dict
] = f"{message['message']} [link](github.com/232323232) {commit.author} {commit.author_email}"
return message

parser = ConventionalCommitsCz.commit_parser
changelog_pattern = ConventionalCommitsCz.bump_pattern
cz = ConventionalCommitsCz(BaseConfig())
parser = cz.commit_parser
changelog_pattern = cz.bump_pattern
tree = changelog.generate_tree_from_commits(
gitcommits,
tags,
Expand Down