Skip to content

feat: pre-release seperated changelog #454

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

Closed
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
51 changes: 31 additions & 20 deletions commitizen/changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,13 @@ def get_commit_tag(commit: GitCommit, tags: List[GitTag]) -> Optional[GitTag]:


def generate_tree_from_commits(
commits: List[GitCommit],
tags: List[GitTag],
commit_parser: str,
changelog_pattern: str = defaults.bump_pattern,
unreleased_version: Optional[str] = None,
change_type_map: Optional[Dict[str, str]] = None,
changelog_message_builder_hook: Optional[Callable] = None,
commits: List[GitCommit],
tags: List[GitTag],
commit_parser: str,
changelog_pattern: str = defaults.bump_pattern,
unreleased_version: Optional[str] = None,
change_type_map: Optional[Dict[str, str]] = None,
changelog_message_builder_hook: Optional[Callable] = None,
) -> Iterable[Dict]:
pat = re.compile(changelog_pattern)
map_pat = re.compile(commit_parser, re.MULTILINE)
Expand Down Expand Up @@ -169,13 +169,25 @@ def render_changelog(tree: Iterable) -> str:
return changelog


def parse_version_from_markdown(value: str) -> Optional[str]:
def parse_version_from_markdown(value: str, pr_filter: str) -> Optional[str]:
"""
:param pr_filter: pass to only find a certain type of version, or None for any
version type. Example: when there is 1.0.0 and 2.0.0b1 and you pass "" 1.0.0 will be returned
as it is the last release.
"""
if not value.startswith("#"):
return None
if not value.__contains__(pr_filter):
return None
m = re.search(defaults.version_parser, value)
if not m:
return None
return m.groupdict().get("version")
version = m.groupdict().get("version")
# when pr_filter is provided but empty
is_stable = re.match(defaults.stable_parser, version)
if not is_stable and pr_filter == "":
return None # because the version is a pre-release but a "full" release is expected
return version


def parse_title_type_of_line(value: str) -> Optional[str]:
Expand All @@ -186,7 +198,7 @@ def parse_title_type_of_line(value: str) -> Optional[str]:
return m.groupdict().get("title")


def get_metadata(filepath: str) -> Dict:
def get_metadata(filepath: str, pr_filter: str) -> Dict:
unreleased_start: Optional[int] = None
unreleased_end: Optional[int] = None
unreleased_title: Optional[str] = None
Expand All @@ -213,13 +225,13 @@ def get_metadata(filepath: str) -> Dict:
unreleased_title = unreleased
continue
elif (
isinstance(unreleased_title, str)
and parse_title_type_of_line(line) == unreleased_title
isinstance(unreleased_title, str)
and parse_title_type_of_line(line) == unreleased_title
):
unreleased_end = index

# Try to find the latest release done
version = parse_version_from_markdown(line)
version = parse_version_from_markdown(line, pr_filter)
if version:
latest_version = version
latest_version_position = index
Expand Down Expand Up @@ -259,21 +271,20 @@ def incremental_build(new_content: str, lines: List, metadata: Dict) -> List:
elif index == unreleased_end:
skip = False
if (
latest_version_position is None
or isinstance(latest_version_position, int)
and isinstance(unreleased_end, int)
and latest_version_position > unreleased_end
latest_version_position is None
or isinstance(latest_version_position, int)
and isinstance(unreleased_end, int)
and latest_version_position > unreleased_end
):
continue

if skip:
continue

if (
isinstance(latest_version_position, int)
and index == latest_version_position
isinstance(latest_version_position, int)
and index == latest_version_position
):

output_lines.append(new_content)
output_lines.append("\n")

Expand Down
15 changes: 14 additions & 1 deletion commitizen/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,19 @@
"action": "store_true",
"help": "accept automatically questions done",
},
{
"name": "--separate-pre-changelog",
"action": "store_true",
"default": False,
"help": "use a separate changelog for each type of prerelease"
},
{
"name": "--separate-pre-releases",
"action": "store_true",
"default": False,
"help": "changes in the changelog will always relate to the latest "
"release of the same pre-release"
},
{
"name": "--tag-format",
"help": (
Expand Down Expand Up @@ -260,7 +273,7 @@
"exclusive_group": "group1",
},
],
},
}
],
},
}
Expand Down
13 changes: 11 additions & 2 deletions commitizen/commands/changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def similar(a, b):
class Changelog:
"""Generate a changelog based on the commit history."""

def __init__(self, config: BaseConfig, args):
def __init__(self, config: BaseConfig, args: dict):
if not git.is_git_project():
raise NotAGitProjectError()

Expand All @@ -40,6 +40,12 @@ def __init__(self, config: BaseConfig, args):
)
self.dry_run = args["dry_run"]
self.unreleased_version = args["unreleased_version"]
self.separate_pre_releases = args["separate_pre_releases"]
self.separate_pre_changelog = args["separate_pre_changelog"]
self.pre_release = args["prerelease"]
if self.separate_pre_changelog:
self.separate_pre_releases = True
self.file_name = f"{self.file_name}-${self.pre_release}"
self.change_type_map = (
self.config.settings.get("change_type_map") or self.cz.change_type_map
)
Expand Down Expand Up @@ -94,7 +100,10 @@ def __call__(self):
tags = []

if self.incremental:
changelog_meta = changelog.get_metadata(self.file_name)
pr_filter = None
if self.separate_pre_releases:
pr_filter = self.pre_release
changelog_meta = changelog.get_metadata(self.file_name, pr_filter)
latest_version = changelog_meta.get("latest_version")
if latest_version:
start_rev = self._find_incremental_rev(latest_version, tags)
Expand Down
1 change: 1 addition & 0 deletions commitizen/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@

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+)?)"
stable_parser = r"^([0-9]|[1-9][0-9]*)\.([0-9]|[1-9][0-9]*)\.([0-9]|[1-9][0-9]*)$"