Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .cz.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ version_files = [
"README.md:^docker"
]
bump_message = "BUMP: version $current_version → $new_version"
commit_url = "https://github.com/kpn/cz-kpn/commit/$COMMIT_REV"
update_changelog_on_bump = true
kpn_commit_url = "https://github.com/kpn/cz-kpn/commit/$COMMIT_REV"
37 changes: 25 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,20 @@ NEW: Add login screen (#MY-123)

[MORE INFO](./src/cz_kpn/cz_kpn_info.txt)

## Custom configuration

This rules support custom configuration. You can set the following options in your `pyproject.toml` file:

```toml
[tool.commitizen]
# ...
kpn_strict_check = true
kpn_commit_url = "https://github.com/kpn/cz-kpn/commit/$COMMIT_REV"
```

- `kpn_strict_check`: Enable strict mode during `cz check` and `cz commit`.
- `kpn_commit_url`: URL to the commit page on your version control system. Which will be used to generate the changelog.

## Installation

Install globally in your system
Expand Down Expand Up @@ -68,7 +82,7 @@ Just run:
cz bump
```

### Commiting
### Committing

```sh
cz commit
Expand Down Expand Up @@ -149,15 +163,10 @@ More info in [commitizen website](https://commitizen-tools.github.io/commitizen/
cz check --rev-range ugnu348hg84hg84g..j8fj84g84h84hg83h2392
```

### Adding commit link to the changelog

Add to the configuration the `commit_url` parameter, using `$COMMIT_REV` as
variable, you can take a look at this project's [.cz.toml](.cz.toml) as an example
You can also check against the last version:

```toml
[tool.commitizen]
...
commit_url = "https://YOUR_DOMAIN/projects/YOUR_GROUP/repos/YOUR_PROJECT/commits/$COMMIT_REV"
```bash
cz check --rev-range "$(cz version -p).."
```

## Configuration
Expand Down Expand Up @@ -186,15 +195,19 @@ Contents:

```bash
$ cz --help
Commitizen is a cli tool to generate conventional commits.
For more information about the topic go to https://conventionalcommits.org/
usage: cz [-h] [--config CONFIG] [--debug] [-n NAME] [-nr NO_RAISE]
{init,commit,c,ls,example,info,schema,bump,changelog,ch,check,version} ...

Commitizen is a powerful release management tool that helps teams maintain consistent and meaningful commit messages while automating version management.
For more information, please visit https://commitizen-tools.github.io/commitizen

options:
-h, --help show this help message and exit
--config CONFIG the path of configuration file
--debug use debug mode
-n NAME, --name NAME use the given commitizen (default: cz_conventional_commits)
-nr NO_RAISE, --no-raise NO_RAISE
comma separated error codes that won't rise error, e.g: cz -nr 1,2,3 bump. See codes at
comma separated error codes that won't raise error, e.g: cz -nr 1,2,3 bump. See codes at
https://commitizen-tools.github.io/commitizen/exit_codes/

commands:
Expand Down
6 changes: 6 additions & 0 deletions src/cz_kpn/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,9 @@

BUMP_PATTERN = r"^(NEW|CHANGE|FIX|OPT|BREAK)"
COMMIT_PARSER = r"^(?P<change_type>NEW|CHANGE|FIX|OPT|BREAK)(?:\((?P<scope>[^()\r\n]*)\)|\()?:?\s(?P<message>.+)" # noqa
COMMIT_PARSER_STRICT = r"(?P<keyword>BREAK|CHANGE|NEW|FIX|OPT)(\((?=[a-z]))?(?P<scope>(?<=\()(test|ci|docs|build)(?=\)))?((?<=[a-z])\))?: .{3,79} (?P<ticket>\(#[A-Z]+-[0-9]+\)|\(#[0-9]+\))" # noqa


## CUSTOM SETTINGS KEYS
STRICT_CHECK = "kpn_strict_check"
COMMIT_URL = "kpn_commit_url"
48 changes: 44 additions & 4 deletions src/cz_kpn/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,38 @@

from commitizen import git
from commitizen.cz.base import BaseCommitizen
from commitizen.cz.utils import required_validator
from commitizen.question import CzQuestion

from cz_kpn.consts import (
BREAK,
BREAK_DESCR,
BUMP_PATTERN,
COMMIT_PARSER,
COMMIT_PARSER_STRICT,
COMMIT_URL,
FIX,
FIX_DESCR,
NEW,
NEW_DESCR,
OPT,
OPT_DESCR,
STRICT_CHECK,
)


def _parse_subject(text: str) -> str:
value = text.strip(".").strip()
msg = ""
if not value:
msg = "Subject is required."
elif len(value) < 3:
msg = "Subject must be at least 3 characters long."
elif len(value) > 79:
msg = "Subject must be at most 79 characters long."
return required_validator(value, msg=msg)


class KPNCz(BaseCommitizen):
bump_pattern = BUMP_PATTERN
bump_map = {
Expand All @@ -47,6 +63,17 @@ class KPNCz(BaseCommitizen):
"FIX": "Fixes",
}

def parse_issue(self, text: str) -> str:
"""Parse issue ID.

If valid it's converted to uppercase.
if strict enabled, it's required.
"""
kpn_strict = self.config.settings.get(STRICT_CHECK, False)
if kpn_strict:
return required_validator(text.upper(), msg="Issue ID is required")
return text.upper()

def questions(self) -> Iterable[CzQuestion]:
questions: list[CzQuestion] = [
{
Expand All @@ -60,8 +87,18 @@ def questions(self) -> Iterable[CzQuestion]:
{"value": BREAK, "name": f"{BREAK} - {BREAK_DESCR}"},
],
},
{"type": "input", "name": "title", "message": "Short description:\n"},
{"type": "input", "name": "issue", "message": "Issue ID:\n"},
{
"type": "input",
"name": "title",
"message": "Short description:\n",
"filter": _parse_subject,
},
{
"type": "input",
"name": "issue",
"message": "Issue ID:\n",
"filter": self.parse_issue,
},
{"type": "input", "name": "description", "message": "Long description:\n"},
]
return questions
Expand Down Expand Up @@ -99,10 +136,10 @@ def info(self) -> str:
with open(filepath, "r") as f:
return f.read()

def changelog_message_builder_hook( # type: ignore
def changelog_message_builder_hook(
self, message: dict[str, Any], commit: git.GitCommit
) -> dict[str, Any]:
commit_url: str = self.config.settings.get("commit_url") # type: ignore
commit_url: str | None = self.config.settings.get(COMMIT_URL) # type: ignore
if commit_url:
t = Template(commit_url)
url = t.safe_substitute(COMMIT_REV=commit.rev)
Expand All @@ -112,4 +149,7 @@ def changelog_message_builder_hook( # type: ignore
return message

def schema_pattern(self) -> str:
kpn_strict = self.config.settings.get(STRICT_CHECK, False)
if kpn_strict:
return COMMIT_PARSER_STRICT
return COMMIT_PARSER
41 changes: 39 additions & 2 deletions tests/test_commit_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import pytest

try:
from cz_kpn.consts import COMMIT_PARSER
from cz_kpn.consts import COMMIT_PARSER, COMMIT_PARSER_STRICT
except AttributeError:
from cz_kpn.consts import COMMIT_PARSER
from cz_kpn.consts import COMMIT_PARSER, COMMIT_PARSER_STRICT

MESSAGE_AND_VALIDITY = [
("BREAK: New commit with break to bump auto-tag (#3625)", True),
Expand Down Expand Up @@ -40,3 +40,40 @@ def test_parser_regex(message, result):
print(message.groupdict())

assert is_valid == result


STRICT_MESSAGE_AND_VALIDITY = [
("BREAK: New commit with break to bump auto-tag (#3625)", True),
("BREAK: Change foobar into quux (#DE-2053)", True),
("NEW: BaseView for all my generic functionality (#J-1)", True),
("NEW: FancyView using BaseView that does something fancy (#J-2)", True),
("BREAK: Change foobar into quux (#DE-2053)", True),
("BREAK: Foo (#1)", True),
("BREAK: Foo (#99999999)", True),
("OPT: Small fixes for the FancyView", False),
("FIX: Bug in the BaseView", False),
("OPT(test): Written unittests for the FancyView", False),
("FIX: Processed pull-request feedback", False),
("FIX: Missing mock data for FancyView and BaseView", False),
("FIX: Something completely unrelated", False),
("NEW: Add new InboxMessage and Image version (XXX-3083)", False),
("NEW XXX-2966 Add support for teams per campaign", False),
("NEW Add support for teams per campaign", False),
("feat: add stuff", False),
("Add README", False),
("fix stuff", False),
("foo(bar): pepe", False),
("FIX: ", False),
]


@pytest.mark.parametrize("message, result", STRICT_MESSAGE_AND_VALIDITY)
def test_parser_regex_strict(message, result):
map_pat = re.compile(COMMIT_PARSER_STRICT, re.MULTILINE)
print(COMMIT_PARSER_STRICT)
message = map_pat.match(message)
is_valid = bool(message)
if is_valid:
print(message.groupdict())

assert is_valid == result