Skip to content

feature: changelog_message_build_hook can remove message by returning a falsy value #1001

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

Merged
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
10 changes: 8 additions & 2 deletions commitizen/changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@ def generate_tree_from_commits(
change_type = change_type_map.get(change_type, change_type)
if changelog_message_builder_hook:
parsed_message = changelog_message_builder_hook(parsed_message, commit)
changes[change_type].append(parsed_message)
if parsed_message:
changes[change_type].append(parsed_message)

# Process body from commit message
body_parts = commit.body.split("\n\n")
Expand All @@ -179,7 +180,12 @@ def generate_tree_from_commits(
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)
if changelog_message_builder_hook:
parsed_message_body = changelog_message_builder_hook(
parsed_message_body, commit
)
if parsed_message_body:
changes[change_type].append(parsed_message_body)

yield {"version": current_tag_name, "date": current_tag_date, "changes": changes}

Expand Down
3 changes: 2 additions & 1 deletion commitizen/commands/changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from commitizen import bump, changelog, defaults, factory, git, out

from commitizen.config import BaseConfig
from commitizen.cz.base import MessageBuilderHook
from commitizen.exceptions import (
DryRunExit,
NoCommitsFoundError,
Expand Down Expand Up @@ -145,7 +146,7 @@ def __call__(self):
unreleased_version = self.unreleased_version
changelog_meta = changelog.Metadata()
change_type_map: dict | None = self.change_type_map
changelog_message_builder_hook: Callable | None = (
changelog_message_builder_hook: MessageBuilderHook | None = (
self.cz.changelog_message_builder_hook
)
merge_prerelease = self.merge_prerelease
Expand Down
12 changes: 8 additions & 4 deletions commitizen/cz/base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

from abc import ABCMeta, abstractmethod
from typing import Any, Callable
from typing import Any, Callable, Protocol

from jinja2 import BaseLoader, PackageLoader
from prompt_toolkit.styles import Style, merge_styles
Expand All @@ -11,6 +11,12 @@
from commitizen.defaults import Questions


class MessageBuilderHook(Protocol):
def __call__(
self, message: dict[str, Any], commit: git.GitCommit
) -> dict[str, Any] | None: ...


class BaseCommitizen(metaclass=ABCMeta):
bump_pattern: str | None = None
bump_map: dict[str, str] | None = None
Expand All @@ -37,9 +43,7 @@ class BaseCommitizen(metaclass=ABCMeta):
change_type_order: list[str] | None = None

# Executed per message parsed by the commitizen
changelog_message_builder_hook: None | (Callable[[dict, git.GitCommit], dict]) = (
None
)
changelog_message_builder_hook: MessageBuilderHook | None = None

# Executed only at the end of the changelog generation
changelog_hook: Callable[[str, str | None], str] | None = None
Expand Down
10 changes: 5 additions & 5 deletions docs/bump.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,13 @@ by their precedence and showcase how a release might flow through a development

### `--increment-mode`

By default, `--increment-mode` is set to `linear`, which ensures taht bumping pre-releases _maintains linearity_:
bumping of a pre-release with lower precedence than the current pre-release phase maintains the current phase of
higher precedence. For example, if the current version is `1.0.0b1` then bumping with `--prerelease alpha` will
By default, `--increment-mode` is set to `linear`, which ensures that bumping pre-releases _maintains linearity_:
bumping of a pre-release with lower precedence than the current pre-release phase maintains the current phase of
higher precedence. For example, if the current version is `1.0.0b1` then bumping with `--prerelease alpha` will
continue to bump the “beta” phase.

Setting `--increment-mode` to `exact` instructs `cz bump` to instead apply the
exact changes that have been specified with `--increment` or determined from the commit log. For example,
Setting `--increment-mode` to `exact` instructs `cz bump` to instead apply the
exact changes that have been specified with `--increment` or determined from the commit log. For example,
`--prerelease beta` will always result in a `b` tag, and `--increment PATCH` will always increase the patch component.

Below are some examples that illustrate the difference in behavior:
Expand Down
4 changes: 2 additions & 2 deletions docs/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,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 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_message_builder_hook` | `method: (dict, git.GitCommit) -> dict | None` | 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`. Returning a falsy value ignore the 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
Expand All @@ -339,7 +339,7 @@ class StrangeCommitizen(BaseCommitizen):

def changelog_message_builder_hook(
self, parsed_message: dict, commit: git.GitCommit
) -> dict:
) -> dict | None:
rev = commit.rev
m = parsed_message["message"]
parsed_message[
Expand Down
28 changes: 28 additions & 0 deletions tests/test_changelog.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import re

from pathlib import Path

import pytest
Expand Down Expand Up @@ -1319,6 +1321,32 @@ def changelog_message_builder_hook(message: dict, commit: git.GitCommit) -> dict
assert "[link](github.com/232323232) Commitizen author@cz.dev" in result


def test_changelog_message_builder_hook_can_remove_commits(
gitcommits, tags, any_changelog_format: ChangelogFormat
):
def changelog_message_builder_hook(message: dict, commit: git.GitCommit):
return None

parser = ConventionalCommitsCz.commit_parser
changelog_pattern = ConventionalCommitsCz.changelog_pattern
loader = ConventionalCommitsCz.template_loader
template = any_changelog_format.template
tree = changelog.generate_tree_from_commits(
gitcommits,
tags,
parser,
changelog_pattern,
changelog_message_builder_hook=changelog_message_builder_hook,
)
result = changelog.render_changelog(tree, loader, template)

RE_HEADER = re.compile(r"^## v?\d+\.\d+\.\d+(\w)* \(\d{4}-\d{2}-\d{2}\)$")
# Rendered changelog should be empty, only containing version headers
for no, line in enumerate(result.splitlines()):
if line := line.strip():
assert RE_HEADER.match(line), f"Line {no} should not be there: {line}"


def test_get_smart_tag_range_returns_an_extra_for_a_range(tags):
start, end = (
tags[0],
Expand Down