Skip to content

Commit

Permalink
feat(changelog): adds a git tag parser
Browse files Browse the repository at this point in the history
The git tag parser is used to filter out undesired git tags from changelog.
  • Loading branch information
bhelgs committed Jun 1, 2022
1 parent 7916511 commit 1910b96
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 4 deletions.
8 changes: 5 additions & 3 deletions commitizen/changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import re
from collections import OrderedDict, defaultdict
from datetime import date
from typing import Callable, Dict, Iterable, List, Optional, Tuple
from typing import Callable, Dict, Iterable, List, Optional, Pattern, Tuple

from jinja2 import Environment, PackageLoader

Expand Down Expand Up @@ -74,6 +74,7 @@ def generate_tree_from_commits(
unreleased_version: Optional[str] = None,
change_type_map: Optional[Dict[str, str]] = None,
changelog_message_builder_hook: Optional[Callable] = None,
tag_pattern: Pattern = re.compile(".*"),
) -> Iterable[Dict]:
pat = re.compile(changelog_pattern)
map_pat = re.compile(commit_parser, re.MULTILINE)
Expand All @@ -97,14 +98,15 @@ def generate_tree_from_commits(
commit_tag = get_commit_tag(commit, tags)

if commit_tag is not None and commit_tag not in used_tags:
matches = tag_pattern.fullmatch(commit_tag.name)
if not matches:
continue
used_tags.append(commit_tag)
yield {
"version": current_tag_name,
"date": current_tag_date,
"changes": changes,
}
# 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
changes = defaultdict(list)
Expand Down
1 change: 1 addition & 0 deletions commitizen/commands/changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ def __call__(self):
unreleased_version,
change_type_map=change_type_map,
changelog_message_builder_hook=changelog_message_builder_hook,
tag_pattern=self.cz.tag_pattern,
)
if self.change_type_order:
tree = changelog.order_changelog_tree(tree, self.change_type_order)
Expand Down
7 changes: 6 additions & 1 deletion commitizen/cz/base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import re
from abc import ABCMeta, abstractmethod
from typing import Callable, Dict, List, Optional, Tuple
from typing import Callable, Dict, List, Optional, Pattern, Tuple

from prompt_toolkit.styles import Style, merge_styles

Expand Down Expand Up @@ -31,6 +32,8 @@ class BaseCommitizen(metaclass=ABCMeta):
changelog_pattern: Optional[str] = r".*"
change_type_map: Optional[Dict[str, str]] = None
change_type_order: Optional[List[str]] = None
tag_parser = ".*"
tag_pattern: Pattern

# Executed per message parsed by the commitizen
changelog_message_builder_hook: Optional[
Expand All @@ -45,6 +48,8 @@ def __init__(self, config: BaseConfig):
if not self.config.settings.get("style"):
self.config.settings.update({"style": BaseCommitizen.default_style_config})

self.tag_pattern = re.compile(self.tag_parser)

@abstractmethod
def questions(self) -> Questions:
"""Questions regarding the commit message."""
Expand Down
4 changes: 4 additions & 0 deletions commitizen/cz/customize/customize.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ def __init__(self, config: BaseConfig):
if change_type_map:
self.change_type_map = change_type_map

tag_parser = self.custom_settings.get("tag_pattern")
if tag_parser:
self.tag_parser = str(tag_parser)

def questions(self) -> Questions:
return self.custom_settings.get("questions", [{}])

Expand Down
7 changes: 7 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,13 @@ cz changelog --start-rev="v0.2.0"
changelog_start_rev = "v0.2.0"
```
### `tag_parser`
This value can be set om the `toml` file with the key `tag_parser` under `tools.commitizen`
Be default the changlog will capture all git tag (e.g. regex `.*`). To specify a tag pattern the user may create a regex pattern to for whichever tags they would like captured.
Any tag that does not match is effectively treated as if it does not exist.
## Hooks
Supported hook methods:
Expand Down
2 changes: 2 additions & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ commitizen:
| `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] |
| `tag_parser ` | `str` | `.*` | Generate changelog using only tags matching the regex pattern (e.g. `"v([0-9.])*"`). [See more][tag_parser] |
| `update_changelog_on_bump` | `bool` | `false` | Create changelog when running `cz bump` |
| `annotated_tag` | `bool` | `false` | Use annotated tags instead of lightweight tags. [See difference][annotated-tags-vs-lightweight] |
| `bump_message` | `str` | `None` | Create custom commit message, useful to skip ci. [See more][bump_message] |
Expand All @@ -142,6 +143,7 @@ commitizen:
[version_files]: bump.md#version_files
[tag_format]: bump.md#tag_format
[bump_message]: bump.md#bump_message
[tag_parser]: changelog.md#tag_parser
[allow_abort]: check.md#allow-abort
[additional-features]: https://github.com/tmbo/questionary#additional-features
[customization]: customization.md
Expand Down
40 changes: 40 additions & 0 deletions tests/test_changelog.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import re
from typing import Dict, Iterable, List, Pattern

import pytest

from commitizen import changelog, defaults, git
Expand Down Expand Up @@ -790,6 +793,26 @@ def test_get_commit_tag_is_None(gitcommits, tags):
)


def _filter_tree(tag_pattern: Pattern, tree: Iterable[Dict]) -> List[Dict[str, str]]:
"""filters the tree. commits with invalid tags are kept within the current node"""

current = None
out = []
for node in tree:
if not current or tag_pattern.fullmatch(node["version"]) or not out:
current = node.copy()
out.append(current)
else:
changes = current["changes"]
for key, value in node["changes"].items():
if key in changes:
changes[key].extend(value)
else:
changes[key] = value

return out


def test_generate_tree_from_commits(gitcommits, tags):
parser = defaults.commit_parser
changelog_pattern = defaults.bump_pattern
Expand All @@ -800,6 +823,23 @@ def test_generate_tree_from_commits(gitcommits, tags):
assert tuple(tree) == COMMITS_TREE


def test_generate_tree_from_commits_release_filter(gitcommits, tags):
parser = defaults.commit_parser
changelog_pattern = defaults.bump_pattern

# match release tags only
tag_parser = r"v([0-9]+)\.([0-9]+)\.([0-9]+)"
tag_pattern = re.compile(tag_parser)

tree = changelog.generate_tree_from_commits(
gitcommits, tags, parser, changelog_pattern, tag_pattern=tag_pattern
)

expected_tree = _filter_tree(tag_pattern, COMMITS_TREE)

assert list(tree) == expected_tree


@pytest.mark.parametrize(
"change_type_order, expected_reordering",
(
Expand Down

3 comments on commit 1910b96

@hongkongkiwi
Copy link

Choose a reason for hiding this comment

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

This doesn't work with the cz changelog command :/ it still shows my unrelated tags.

@bhelgs
Copy link
Owner Author

@bhelgs bhelgs commented on 1910b96 Jun 28, 2022

Choose a reason for hiding this comment

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

@hongkongkiwi, thanks for bringing this to my attention. I was off last week, I'll take a look back at this in a day or two.

@bhelgs
Copy link
Owner Author

@bhelgs bhelgs commented on 1910b96 Jul 20, 2022

Choose a reason for hiding this comment

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

This doesn't work with the cz changelog command :/ it still shows my unrelated tags.

fixed in the PR. Thanks for pointing out that I had missed the CLI test.

Please sign in to comment.