-
Notifications
You must be signed in to change notification settings - Fork 2
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
Support PEP 440 #15
base: main
Are you sure you want to change the base?
Support PEP 440 #15
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,27 @@ | ||
from typing import NamedTuple, Optional | ||
import re | ||
from typing import NamedTuple, Optional, Tuple | ||
|
||
|
||
_REGEX_PRE = re.compile(r"^(?P<id>(a|b|rc))(?P<val>\d+)$") | ||
|
||
|
||
class Version(NamedTuple): | ||
major: int | ||
minor: int | ||
patch: int | ||
release: Tuple[int, ...] | ||
epoch: Optional[int] = None | ||
pre: Optional[str] = None | ||
post: Optional[int] = None | ||
dev: Optional[int] = None | ||
commit: Optional[str] = None | ||
|
||
def __str__(self) -> str: | ||
if not self.commit: | ||
return f"{self.major}.{self.minor}.{self.patch}" | ||
return f"{self.major}.{self.minor}.{self.patch}+g{self.commit}" | ||
epoch = f"{self.epoch}!" if self.epoch is not None else "" | ||
pre = self.pre or "" | ||
post = f".post{self.post}" if self.post is not None else "" | ||
dev = f".dev{self.dev}" if self.dev is not None else "" | ||
commit = f"+{self.commit}" if self.commit is not None else "" | ||
version = ( | ||
epoch + | ||
".".join(map(str, self.release)) + | ||
"".join((pre, post, dev, commit)) | ||
) | ||
return version |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,10 +3,10 @@ | |
import warnings | ||
from dataclasses import dataclass | ||
from shutil import which | ||
from types import MappingProxyType | ||
from typing import Any, Callable, ClassVar, Mapping, Match, Optional | ||
|
||
from poem_plugins.config.git import GitProviderSettings, GitVersionFormatEnum | ||
from poem_plugins.config.git import ( | ||
GitProviderSettings, GitVersionFormatEnum, VersionSegmentBumpEnum, | ||
) | ||
from poem_plugins.general.version import Version | ||
from poem_plugins.general.version.drivers import IVersionDriver | ||
|
||
|
@@ -32,17 +32,59 @@ class GitVersionDriver(IVersionDriver): | |
'__version__ = "{version}"\n' | ||
) | ||
|
||
CONVERTERS: ClassVar[ | ||
Mapping[str, Callable[[Any], Any]] | ||
] = MappingProxyType( | ||
{ | ||
"major": int, | ||
"minor": int, | ||
"patch": int, | ||
}, | ||
) | ||
def _get_version_pep_440(self, raw_version: str) -> Version: | ||
if raw_version.startswith(self.settings.version_prefix): | ||
raw_version = raw_version.removeprefix(self.settings.version_prefix) | ||
else: | ||
raise RuntimeError( | ||
f"Version tag must start with '{self.settings.version_prefix}' " | ||
f"as defined in the plugin's config (or by default).", | ||
) | ||
regex = ( | ||
r"^((?P<epoch>\d+)!)?(?P<release>\d+(\.\d+)*)" | ||
r"(?P<pre>(a|b|rc)\d+)?(\.post(?P<post>\d+))?(\.dev(?P<dev>\d+))?" | ||
r"-(?P<commit_count>\d+)-(?P<commit>\S+)$" | ||
) | ||
match = re.match(regex, raw_version) | ||
if not match: | ||
raise RuntimeError( | ||
f"Failed to parse git version: '{raw_version}' must conform to " | ||
f"PEP 440", | ||
) | ||
groups = match.groupdict() | ||
epoch = groups["epoch"] | ||
pre, post, dev = groups["pre"], groups["post"], groups["dev"] | ||
commit_count = int(groups["commit_count"]) | ||
commit = groups["commit"] | ||
release = list(map(int, groups["release"].split("."))) | ||
if len(release) < 3: | ||
release += [0] * (3 - len(release)) | ||
|
||
def get_version(self) -> Version: | ||
segments = { | ||
"epoch": int(epoch) if epoch is not None else None, | ||
"pre": pre, | ||
"post": int(post) if post is not None else None, | ||
"dev": int(dev) if dev is not None else None, | ||
"commit": commit, | ||
} | ||
|
||
if commit_count: | ||
bump_segment = self.settings.bump_segment | ||
if bump_segment == VersionSegmentBumpEnum.RELEASE: | ||
print(release) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems redundant |
||
release[-1] += commit_count | ||
else: | ||
segments[bump_segment.value] = segments[bump_segment.value] or 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. bump_segment is a StrEnum, does it need to get |
||
segments[bump_segment.value] += commit_count # type: ignore | ||
|
||
segments["release"] = tuple(release) | ||
|
||
if self.settings.format == GitVersionFormatEnum.SHORT: | ||
segments["commit"] = None | ||
|
||
return Version(**segments) # type: ignore | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why ignore here? |
||
|
||
def _git_describe(self) -> str: | ||
if GIT_BIN is None: | ||
raise RuntimeError(WARNING_TEXT) | ||
|
||
|
@@ -53,36 +95,21 @@ def get_version(self) -> Version: | |
) | ||
|
||
if result.returncode != 0: | ||
raise RuntimeError("Cannot found git version") | ||
raw_version = result.stdout.strip() | ||
regex = ( | ||
r"(?P<major>\d+)\.(?P<minor>\d+)-(?P<patch>\d+)-(?P<commit>\S+)" | ||
) | ||
match: Optional[Match[str]] = re.match( | ||
self.settings.version_prefix + regex, | ||
raw_version, | ||
) | ||
raise RuntimeError("Failed to find git version tag") | ||
return result.stdout.strip() | ||
|
||
if match is None: | ||
raise RuntimeError("Cannot parse git version") | ||
raw_kwargs = dict(match.groupdict()) | ||
if self.settings.format == GitVersionFormatEnum.SHORT: | ||
raw_kwargs.pop("commit", None) | ||
kwargs = { | ||
k: self.CONVERTERS.get(k, lambda x: x)(v) | ||
for k, v in raw_kwargs.items() | ||
} | ||
|
||
return Version(**kwargs) | ||
def get_version(self) -> Version: | ||
raw_version = self._git_describe() | ||
return self._get_version_pep_440(raw_version) | ||
|
||
def render_version_file( | ||
self, | ||
version: Version, | ||
) -> str: | ||
return self.VERSION_TEMPLATE.format( | ||
whoami='poem-plugins "git" plugin', | ||
major=version.major, | ||
minor=version.minor, | ||
patch=version.patch, | ||
major=version.release[0], | ||
minor=version.release[1], | ||
patch=version.release[2], | ||
version=str(version), | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import pytest | ||
|
||
from poem_plugins.config.git import ( | ||
GitProviderSettings, GitVersionFormatEnum, VersionSegmentBumpEnum, | ||
) | ||
from poem_plugins.general.version import Version | ||
|
||
|
||
@pytest.fixture | ||
def git_settings() -> GitProviderSettings: | ||
return GitProviderSettings(format=GitVersionFormatEnum.SHORT) | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"describe,segment,expected", ( | ||
( | ||
"1", | ||
VersionSegmentBumpEnum.RELEASE, | ||
Version(release=(1, 0, 10)), | ||
), | ||
( | ||
"1.2", | ||
VersionSegmentBumpEnum.RELEASE, | ||
Version(release=(1, 2, 10)), | ||
), | ||
( | ||
"1.2.3", | ||
VersionSegmentBumpEnum.RELEASE, | ||
Version(release=(1, 2, 13)), | ||
), | ||
( | ||
"1.2.3.4", | ||
VersionSegmentBumpEnum.RELEASE, | ||
Version(release=(1, 2, 3, 14)), | ||
), | ||
( | ||
"1.2.post3", | ||
VersionSegmentBumpEnum.POST_RELEASE, | ||
Version(release=(1, 2, 0), post=13), | ||
), | ||
( | ||
"1.2.dev3", | ||
VersionSegmentBumpEnum.DEV, | ||
Version(release=(1, 2, 0), dev=13), | ||
), | ||
), | ||
) | ||
def test_pep_440( | ||
get_mocked_git_version_driver, describe, segment, expected, | ||
) -> None: | ||
describe = "v" + describe + "-10-g3c3e199" | ||
|
||
git_settings = GitProviderSettings(bump_segment=segment) | ||
driver = get_mocked_git_version_driver(describe=describe, git_settings=git_settings) | ||
assert driver.get_version() == expected | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"describe,segment,expected", ( | ||
( | ||
"1.2.3.4", | ||
VersionSegmentBumpEnum.RELEASE, | ||
Version(release=(1, 2, 3, 4)), | ||
), | ||
( | ||
"1.2", | ||
VersionSegmentBumpEnum.POST_RELEASE, | ||
Version(release=(1, 2, 0)), | ||
), | ||
( | ||
"1.2", | ||
VersionSegmentBumpEnum.DEV, | ||
Version(release=(1, 2, 0)), | ||
), | ||
), | ||
) | ||
def test_pep_440_zero_commits( | ||
get_mocked_git_version_driver, describe, segment, expected, | ||
) -> None: | ||
describe = "v" + describe + "-0-g3c3e199" | ||
|
||
git_settings = GitProviderSettings(bump_segment=segment) | ||
driver = get_mocked_git_version_driver(describe=describe, git_settings=git_settings) | ||
assert driver.get_version() == expected |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
specify please typed dict to avoid using ingore