Skip to content

Commit

Permalink
refactor: Ignore tags that are not valid given versioning scheme
Browse files Browse the repository at this point in the history
Co-authored-by: Christian Meffert <chme@users.noreply.github.com>
  • Loading branch information
pawamoy and chme committed Apr 1, 2024
1 parent 2e017e9 commit 5fdc68a
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 26 deletions.
40 changes: 17 additions & 23 deletions src/git_changelog/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import sys
import warnings
from subprocess import CalledProcessError, check_output
from typing import TYPE_CHECKING, Callable, ClassVar, Literal, Type, Union
from typing import TYPE_CHECKING, ClassVar, Literal, Type, Union
from urllib.parse import urlsplit, urlunsplit

from git_changelog.commit import (
Expand All @@ -18,7 +18,7 @@
ConventionalCommitConvention,
)
from git_changelog.providers import Bitbucket, GitHub, GitLab, ProviderRefParser
from git_changelog.versioning import ParsedVersion, VersionBumper, bump_pep440, bump_semver, parse_pep440, parse_semver
from git_changelog.versioning import ParsedVersion, bump_pep440, bump_semver, parse_pep440, parse_semver

if TYPE_CHECKING:
from pathlib import Path
Expand Down Expand Up @@ -266,20 +266,20 @@ def __init__(
)
self.sections = sections

# get version parser based on selected versioning scheme
self.version_parser, self.version_bumper = {
"semver": (parse_semver, bump_semver),
"pep440": (parse_pep440, bump_pep440),
}[versioning]

# get git log and parse it into list of commits
self.raw_log: str = self.get_log()
self.commits: list[Commit] = self.parse_commits()
self.tag_commits: list[Commit] = [commit for commit in self.commits[1:] if commit.tag]
self.tag_commits.insert(0, self.commits[0])

# get version parser based on selected versioning scheme
version_parser, version_bumper = {
"semver": (parse_semver, bump_semver),
"pep440": (parse_pep440, bump_pep440),
}[versioning]

# apply dates to commits and group them by version
v_list, v_dict = self._group_commits_by_version(version_parser=version_parser)
v_list, v_dict = self._group_commits_by_version()
self.versions_list = v_list
self.versions_dict = v_dict

Expand All @@ -293,7 +293,7 @@ def __init__(
if bump is None:
bump = "auto"
if bump:
self._bump(bump, version_bumper=version_bumper)
self._bump(bump)

# fix a single, initial version to the user specified version or 0.1.0 if none is specified
self._fix_single_version(bump)
Expand Down Expand Up @@ -386,6 +386,7 @@ def parse_commits(self) -> list[Commit]:
subject=lines[pos + 9],
body=body,
parse_trailers=self.parse_trailers,
version_parser=self.version_parser,
)

pos += nbl_index + 1
Expand All @@ -406,19 +407,12 @@ def parse_commits(self) -> list[Commit]:

return list(commits_map.values())

def _group_commits_by_version(
self,
version_parser: Callable[[str], tuple[ParsedVersion, str]],
) -> tuple[list[Version], dict[str, Version]]:
def _group_commits_by_version(self) -> tuple[list[Version], dict[str, Version]]:
"""Group commits into versions.
Commits are assigned to the version they were first released with.
A commit is assigned to exactly one version.
Parameters:
version_parser: Version parser to use when grouping commits by versions.
Versions that cannot be parsed by the given parser will be ignored.
Returns:
versions_list: The list of versions order descending by timestamp.
versions_dict: A dictionary of versions with the tag name as keys.
Expand All @@ -441,7 +435,7 @@ def _group_commits_by_version(
while next_commits:
next_commit = next_commits.pop(0)
if next_commit.tag:
parsed_version, _ = version_parser(next_commit.tag)
parsed_version, _ = self.version_parser(next_commit.tag)
if not previous_parsed_version or parsed_version > previous_parsed_version:
previous_parsed_version = parsed_version
previous_versions[version.tag] = next_commit.tag
Expand Down Expand Up @@ -484,7 +478,7 @@ def _assign_previous_versions(self, versions_dict: dict[str, Version], previous_
target=version.tag or "HEAD",
)

def _bump(self, version: str, version_bumper: VersionBumper) -> None:
def _bump(self, version: str) -> None:
last_version = self.versions_list[0]
if not last_version.tag and last_version.previous_version:
last_tag = last_version.previous_version.tag
Expand All @@ -499,13 +493,13 @@ def _bump(self, version: str, version_bumper: VersionBumper) -> None:
if commit.convention["is_minor"]:
version = "minor"
version = "+".join((version, *plus))
if version in version_bumper.strategies:
if version in self.version_bumper.strategies:
# bump version
last_version.planned_tag = version_bumper(last_tag, version, zerover=self.zerover)
last_version.planned_tag = self.version_bumper(last_tag, version, zerover=self.zerover)
else:
# user specified version
try:
version_bumper(version)
self.version_bumper(version)
except ValueError as error:
raise ValueError(f"{error}; typo in bumping strategy? Check the CLI help and our docs") from error
last_version.planned_tag = version
Expand Down
18 changes: 15 additions & 3 deletions src/git_changelog/commit.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
from collections import defaultdict
from contextlib import suppress
from datetime import datetime, timezone
from typing import TYPE_CHECKING, Any, ClassVar, Pattern
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Pattern

if TYPE_CHECKING:
from git_changelog.providers import ProviderRefParser, Ref
from git_changelog.versioning import ParsedVersion


def _clean_body(lines: list[str]) -> list[str]:
Expand All @@ -21,6 +22,14 @@ def _clean_body(lines: list[str]) -> list[str]:
return lines


def _is_valid_version(version: str, version_parser: Callable[[str], tuple[ParsedVersion, str]]) -> bool:
try:
version_parser(version)
except ValueError:
return False
return True


class Commit:
"""A class to represent a commit."""

Expand All @@ -41,6 +50,7 @@ def __init__(
parse_trailers: bool = False,
parent_hashes: str | list[str] = "",
commits_map: dict[str, Commit] | None = None,
version_parser: Callable[[str], tuple[ParsedVersion, str]] | None = None,
):
"""Initialization method.
Expand Down Expand Up @@ -82,8 +92,10 @@ def __init__(
for ref in refs.split(","):
ref = ref.strip() # noqa: PLW2901
if ref.startswith("tag: "):
tag = ref.replace("tag: ", "")
break
ref = ref.replace("tag: ", "") # noqa: PLW2901
if version_parser is None or _is_valid_version(ref, version_parser):
tag = ref
break
self.tag: str = tag
self.version: str = tag

Expand Down
33 changes: 33 additions & 0 deletions tests/test_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,36 @@ def test_build_changelog_with_pep440_versions(repo: GitRepo) -> None:
changelog = Changelog(repo.path, convention=AngularConvention, versioning="pep440")
assert len(changelog.versions_list) == 3
assert changelog.versions_list[1].tag == "1.0.0.post0"


def test_ignore_nonsemver_tag(repo: GitRepo) -> None:
"""Test parsing and grouping commits to versions.
Commit graph:
1.0.0
|
main A-B-C
|
dummy
Expected:
- 1.0.0: C B A
Parameters:
repo: GitRepo to a temporary repository.
"""
commit_a = repo.first_hash
commit_b = repo.commit("fix: B")
repo.tag("dummy")
commit_c = repo.commit("feat: C")
repo.tag("1.0.0")

changelog = Changelog(repo.path, convention=AngularConvention)

assert len(changelog.versions_list) == 1
_assert_version(
changelog.versions_list[0],
expected_tag="1.0.0",
expected_prev_tag=None,
expected_commits=[commit_c, commit_b, commit_a],
)

0 comments on commit 5fdc68a

Please sign in to comment.