Skip to content

Commit

Permalink
feat(changelog): add merge_prereleases flag
Browse files Browse the repository at this point in the history
  • Loading branch information
MoritzBoehme committed Apr 13, 2023
1 parent 378a428 commit d5f6722
Show file tree
Hide file tree
Showing 15 changed files with 481 additions and 6 deletions.
20 changes: 17 additions & 3 deletions commitizen/changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from typing import Callable, Dict, Iterable, List, Optional, Tuple

from jinja2 import Environment, PackageLoader
from packaging.version import InvalidVersion, Version

from commitizen import defaults
from commitizen.bump import normalize_tag
Expand All @@ -43,6 +44,15 @@ def get_commit_tag(commit: GitCommit, tags: List[GitTag]) -> Optional[GitTag]:
return next((tag for tag in tags if tag.rev == commit.rev), None)


def get_version(tag: GitTag) -> Optional[Version]:
version = None
try:
version = Version(tag.name)
except InvalidVersion:
pass
return version


def generate_tree_from_commits(
commits: List[GitCommit],
tags: List[GitTag],
Expand All @@ -51,6 +61,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,
merge_prerelease: bool = False,
) -> Iterable[Dict]:
pat = re.compile(changelog_pattern)
map_pat = re.compile(commit_parser, re.MULTILINE)
Expand All @@ -73,15 +84,18 @@ def generate_tree_from_commits(
for commit in commits:
commit_tag = get_commit_tag(commit, tags)

if commit_tag is not None and commit_tag not in used_tags:
if (
commit_tag is not None
and commit_tag not in used_tags
and get_version(commit_tag) is not None
and not (merge_prerelease and get_version(commit_tag).is_prerelease)
):
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
11 changes: 10 additions & 1 deletion commitizen/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,19 @@
"name": "--start-rev",
"default": None,
"help": (
"start rev of the changelog."
"start rev of the changelog. "
"If not set, it will generate changelog from the start"
),
},
{
"name": "--merge-prerelease",
"action": "store_true",
"default": False,
"help": (
"collect all changes from prereleases into next non-prerelease. "
"If not set, it will include prereleases in the changelog"
),
},
],
},
{
Expand Down
5 changes: 5 additions & 0 deletions commitizen/commands/changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ def __init__(self, config: BaseConfig, args):
self.tag_format = args.get("tag_format") or self.config.settings.get(
"tag_format"
)
self.merge_prerelease = args.get(
"merge_prerelease"
) or self.config.settings.get("changelog_merge_prerelease")

def _find_incremental_rev(self, latest_version: str, tags: List[GitTag]) -> str:
"""Try to find the 'start_rev'.
Expand Down Expand Up @@ -110,6 +113,7 @@ def __call__(self):
changelog_message_builder_hook: Optional[
Callable
] = self.cz.changelog_message_builder_hook
merge_prerelease = self.merge_prerelease

if not changelog_pattern or not commit_parser:
raise NoPatternMapError(
Expand Down Expand Up @@ -158,6 +162,7 @@ def __call__(self):
unreleased_version,
change_type_map=change_type_map,
changelog_message_builder_hook=changelog_message_builder_hook,
merge_prerelease=merge_prerelease,
)
if self.change_type_order:
tree = changelog.order_changelog_tree(tree, self.change_type_order)
Expand Down
2 changes: 2 additions & 0 deletions commitizen/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Settings(TypedDict, total=False):
changelog_file: str
changelog_incremental: bool
changelog_start_rev: Optional[str]
changelog_merge_prerelease: bool
update_changelog_on_bump: bool
use_shortcuts: bool
style: Optional[List[Tuple[str, str]]]
Expand Down Expand Up @@ -69,6 +70,7 @@ class Settings(TypedDict, total=False):
"changelog_file": "CHANGELOG.md",
"changelog_incremental": False,
"changelog_start_rev": None,
"changelog_merge_prerelease": False,
"update_changelog_on_bump": False,
"use_shortcuts": False,
"major_version_zero": False,
Expand Down
20 changes: 19 additions & 1 deletion docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ optional arguments:
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
start rev of the changelog. If not set, it will generate changelog from the start
--merge-prerelease
collect all changes from prereleases into next non-prerelease. If not set, it will include prereleases in the changelog
```
### Examples
Expand Down Expand Up @@ -161,6 +163,22 @@ cz changelog --start-rev="v0.2.0"
changelog_start_rev = "v0.2.0"
```
### merge-prerelease
This flag can be set in the `toml` file with the key `changelog_merge_prerelease` under `tools.commitizen`
Collects changes from prereleases into the next non-prerelease. This means that if you have a prerelease version, and then a normal release, the changelog will show the prerelease changes as part of the changes of the normal release. If not set, it will include prereleases in the changelog.
```bash
cz changelog --merge-prerelease
```
```toml
[tools.commitizen]
# ...
changelog_merge_prerelease = true
```
## Hooks
Supported hook methods:
Expand Down
2 changes: 1 addition & 1 deletion docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
| `allow_abort` | `bool` | `false` | Disallow empty commit messages, useful in ci. [See more][allow_abort] |
| `changelog_file` | `str` | `CHANGELOG.md` | filename of exported changelog |
| `changelog_incremental` | `bool` | `false` | Update changelog with the missing versions. This is good if you don't want to replace previous versions in the file. Note: when doing `cz bump --changelog` this is automatically set to `true` |
| `changelog_start_rev` | `str` | `None` | Start from a given git rev to generate the changelog |
| `changelog_merge_prerelease` | `bool` | `false` | Collect all changes of prerelease versions into the next non-prerelease version when creating the 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] |
Expand Down
68 changes: 68 additions & 0 deletions tests/commands/test_changelog_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,40 @@ def test_changelog_config_flag_increment(
file_regression.check(out, extension=".md")


@pytest.mark.parametrize("test_input", ["rc", "alpha", "beta"])
@pytest.mark.usefixtures("tmp_commitizen_project")
def test_changelog_config_flag_merge_prerelease(
mocker: MockFixture, changelog_path, config_path, file_regression, test_input
):
with open(config_path, "a") as f:
f.write("changelog_merge_prerelease = true\n")

create_file_and_commit("irrelevant commit")
mocker.patch("commitizen.git.GitTag.date", "1970-01-01")
git.tag("1.0.0")

create_file_and_commit("feat: add new output")
create_file_and_commit("fix: output glitch")

testargs = ["cz", "bump", "--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"]

mocker.patch.object(sys, "argv", testargs)
cli.main()

with open(changelog_path, "r") as f:
out = f.read()

file_regression.check(out, extension=".md")


@pytest.mark.usefixtures("tmp_commitizen_project")
def test_changelog_config_start_rev_option(
mocker: MockFixture, capsys, config_path, file_regression
Expand Down Expand Up @@ -549,6 +583,40 @@ def test_changelog_incremental_with_release_candidate_version(
file_regression.check(out, extension=".md")


@pytest.mark.parametrize("test_input", ["rc", "alpha", "beta"])
@pytest.mark.usefixtures("tmp_commitizen_project")
def test_changelog_release_candidate_version_with_merge_prerelease(
mocker: MockFixture, 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")
mocker.patch("commitizen.git.GitTag.date", "1970-01-01")
git.tag("1.0.0")

create_file_and_commit("feat: add new output")
create_file_and_commit("fix: output glitch")

testargs = ["cz", "bump", "--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", "--merge-prerelease"]

mocker.patch.object(sys, "argv", testargs)
cli.main()

with open(changelog_path, "r") as f:
out = f.read()

file_regression.check(out, extension=".md")


@pytest.mark.usefixtures("tmp_commitizen_project")
def test_changelog_with_filename_as_empty_string(
mocker: MockFixture, changelog_path, config_path
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## Unreleased

### Feat

- add more stuff
- add new output

### Fix

- mama gotta work
- output glitch

## 1.0.0 (1970-01-01)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## Unreleased

### Feat

- add more stuff
- add new output

### Fix

- mama gotta work
- output glitch

## 1.0.0 (1970-01-01)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## Unreleased

### Feat

- add more stuff
- add new output

### Fix

- mama gotta work
- output glitch

## 1.0.0 (1970-01-01)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## Unreleased

### Feat

- add more stuff
- add new output

### Fix

- mama gotta work
- output glitch

## 1.0.0 (1970-01-01)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## Unreleased

### Feat

- add more stuff
- add new output

### Fix

- mama gotta work
- output glitch

## 1.0.0 (1970-01-01)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## Unreleased

### Feat

- add more stuff
- add new output

### Fix

- mama gotta work
- output glitch

## 1.0.0 (1970-01-01)
Loading

0 comments on commit d5f6722

Please sign in to comment.