Compare commits

...

4 Commits

Author SHA1 Message Date
cclecle
c0d5e4480c fix: code quality 2023-03-17 18:48:18 +00:00
cclecle
2d718d2e4c fix: wrong cls usage in self class 2023-03-17 18:32:38 +00:00
cclecle
525200b1fc trial fix tag_filter 2023-03-17 18:26:11 +00:00
cclecle
70a1c6ef8c start fixing pylint warnings + add docstrings 2023-03-17 18:09:34 +00:00
2 changed files with 136 additions and 35 deletions

View File

@@ -13,7 +13,7 @@ build-backend = "setuptools.build_meta"
[tool.setuptools-git-versioning]
enabled = true
dev_template = "{tag}.post{ccount}"
#tag_filter = "^\\d+\\.\\d+\\.\\d+$"
tag_filter = "^\\d+\\.\\d+\\.\\d+$"
[project]
name = "pygitversionhelper"

View File

@@ -1,13 +1,39 @@
# pygitversionhelper (c) by chacha
#
# pygitversionhelper is licensed under a
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
#
# You should have received a copy of the license along with this
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
"""
This module is the main gitversionhelper file, containing all the code.
This project aim to be kept compact and focused on helping doing handy things with git when it deal with project versions/tags.
"""
from __future__ import annotations
from typing import TYPE_CHECKING
import os
import subprocess
from packaging.version import VERSION_PATTERN as packaging_VERSION_PATTERN
import re
from dataclasses import dataclass
from copy import copy
from packaging.version import VERSION_PATTERN as packaging_VERSION_PATTERN
if TYPE_CHECKING: # Only imports the below statements during type checking
from typing import Union
def _exec(cmd: str, root: str | os.PathLike | None = None) -> list[str]:
"""
Helper function to handle system cmd execution
Args:
cmd: command line to be executed
root: root directory where the command need to be executed
Return:
a list of command's return lines
"""
try:
stdout = subprocess.check_output(cmd, shell=True, text=True, cwd=root)
except subprocess.CalledProcessError as e:
@@ -15,38 +41,83 @@ def _exec(cmd: str, root: str | os.PathLike | None = None) -> list[str]:
lines = stdout.splitlines()
return [line.rstrip() for line in lines if line.rstrip()]
class gitversionhelper:
class head:
class gitversionhelper: # pylint: disable=too-few-public-methods
"""
Main gitversionhelper class
"""
class repository:
"""
class containing methods focusing on repository
"""
@classmethod
def isDirty(cls):
def isDirty(cls) -> bool:
"""
Check if the repository is in dirty state
Return:
True if it is dirty
"""
return True if _exec(f"git status --short") else False
class tag:
"""
class containing methods focusing on tags
"""
__OptDict = {"same_branch": "same_branch"}
__validGitTagSort=["","v:refname","-v:refname","taggerdate","committerdate","-taggerdate","-committerdate"]
@classmethod
def getTags(cls,sort:str = "version:refname"):
def getTags(cls,sort:str = "version:refname") -> list[str]:
"""
retrieve all tags from a repository
Args:
sort: sorting constraints (git format)
Return:
the tags list
"""
if sort not in cls.__validGitTagSort:
raise RuntimeError("sort option not in allowed list")
return _exec(f"git tag -l --sort={sort}")
@classmethod
def getLastTag(cls,**kwargs):
if ((cls.__OptDict["same_branch"] in kwargs) and (kwargs[cls.__OptDict["same_branch"]]==True)):
return _exec(f"git describe --tags --abbrev=0")[0]
else:
tag = _exec("git rev-list --tags --max-count=1")
return _exec(f"git describe --tags {tag[0]}")[0]
def getLastTag(cls,**kwargs) -> Union[str,None]:
"""
retrieve the last tag from a repository
Kwargs:
same_branch(bool): force searching only in the same branch
Return:
the tag
"""
if ((cls.__OptDict["same_branch"] in kwargs) and (kwargs[cls.__OptDict["same_branch"]] is True)):
return _exec("git describe --tags --abbrev=0")[0]
tag = _exec("git rev-list --tags --max-count=1")
return _exec(f"git describe --tags {tag[0]}")[0]
@classmethod
def getDistanceFromLastTag(cls,tag=None,**kwargs):
if (tag == None):
def getDistanceFromTag(cls,tag=None,**kwargs) -> int:
"""
retrieve the distance from tag in the repository
Arguments:
tag: reference tag, if None the most recent one will be used
Kwargs:
same_branch(bool): force searching only in the same branch
Return:
the tag
"""
if (tag is None):
tag = cls.getLastTag(**kwargs)
return _exec(f"git rev-list {tag}..HEAD --count")[0]
return int(_exec(f"git rev-list {tag}..HEAD --count")[0])
class version:
"""
class containing methods focusing on versions
"""
__OptDict = { "version_std": "version_std",
"formated_output": "formated_output",
"output_format": "output_format"}
DefaultInputFormat = "PEP440"
VersionStds = { "SemVer" : { "regex" : r"^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"},
VersionStds = { "SemVer" : { "regex" : r"^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)"\
r"(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)"\
r"(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?"\
r"(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"},
"PEP440" : { "regex" : packaging_VERSION_PATTERN }
}
@@ -54,7 +125,7 @@ class gitversionhelper:
"""
generic version object
"""
__OptDict = { "bump_type": "bump_type",
__OptDict = { "bump_type": "bump_type",
"bump_dev_strategy": "bump_dev_strategy"}
DefaultBumpType = "patch"
BumpTypes = ["major","minor","patch","dev"]
@@ -67,13 +138,17 @@ class gitversionhelper:
post_count:int = 0
raw:str = "0.1.0"
def __init__(self,major,minor,patch,pre_count,post_count,raw):
def __init__(self,major=0,minor=1,patch=0,pre_count=0,post_count=0,raw="0.1.0"):
self.major,self.minor,self.patch,self.pre_count,self.post_count,self.raw = major,minor,patch,pre_count,post_count,raw
@classmethod
def _getBumpDevStrategy(cls,**kwargs):
def _getBumpDevStrategy(cls,**kwargs) -> str:
"""
get selected bump_dev_strategy
Kwargs:
bump_dev_strategy(str): the given bump_dev_strategy (can be None)
Return:
Kwargs given bump_dev_strategy or the default one.
"""
BumpDevStrategy = cls.DefaultBumpDevStrategy
if (cls.__OptDict["bump_dev_strategy"] in kwargs):
@@ -84,9 +159,13 @@ class gitversionhelper:
return BumpDevStrategy
@classmethod
def _getBumpType(cls,**kwargs):
def _getBumpType(cls,**kwargs) -> str:
"""
get selected bump_type
Kwargs:
bump_type(str): the given bump_type (can be None)
Return:
Kwargs given bump_type or the default one.
"""
BumpType = cls.DefaultBumpType
if (cls.__OptDict["bump_type"] in kwargs):
@@ -97,23 +176,31 @@ class gitversionhelper:
return BumpType
def bump(self,**kwargs):
"""
bump the version to the next one
Kwargs:
bump_type(str): the given bump_type (can be None)
bump_dev_strategy(str): the given bump_dev_strategy (can be None)
Return:
the bumped version
"""
BumpType = self._getBumpType(**kwargs)
BumpDevStrategy=self._getBumpDevStrategy(**kwargs)
_v=copy(self)
if BumpType == "dev":
if BumpDevStrategy=="post":
if BumpDevStrategy == "post":
if _v.pre_count > 0:
_v.pre_count = _v.pre_count + 1
else:
_v.post_count = _v.post_count + 1
elif BumpDevStrategy=="pre":
elif BumpDevStrategy == "pre":
if _v.post_count > 0:
_v.post_count = _v.post_count + 1
else:
_v.pre_count = _v.pre_count + 1
elif BumpDevStrategy=="force_post":
elif BumpDevStrategy == "force_post":
pass
elif BumpDevStrategy=="force_pre":
elif BumpDevStrategy == "force_pre":
pass
else:
if BumpType == "major":
@@ -125,7 +212,7 @@ class gitversionhelper:
_v.pre_count=0
_v.post_count=0
_v.raw="{major}.{minor}.{patch}".format(major=_v.major,minor=_v.minor,patch=_v.patch,revpattern="",revcount="")
_v.raw="{major}.{minor}.{patch}{revpattern}{revcount}".format(major=_v.major,minor=_v.minor,patch=_v.patch,revpattern="",revcount="")
return _v
def doFormatVersion(self,**kwargs):
@@ -135,6 +222,10 @@ class gitversionhelper:
def _getVersionStd(cls,**kwargs):
"""
get selected version_std
Kwargs:
version_std(str): the given version_std (can be None)
Return:
Kwargs given version_std or the default one.
"""
VersionStd = cls.DefaultInputFormat
if (cls.__OptDict["version_std"] in kwargs):
@@ -145,9 +236,15 @@ class gitversionhelper:
return VersionStd
@classmethod
def getLastVersion(cls,**kwargs):
def getLastVersion(cls,**kwargs) -> Union[str,MetaVersion]:
"""
get last version from git tags
bump the last version from tags
Kwargs:
version_std(str): the given version_std (can be None)
same_branch(bool): force searching only in the same branch
formated_output(bool) : output a formated version string
Return:
the last version
"""
VersionStd = cls._getVersionStd(**kwargs)
_r=re.compile(r"^\s*" + cls.VersionStds[VersionStd]["regex"] + r"\s*$", re.VERBOSE | re.IGNORECASE)
@@ -157,7 +254,7 @@ class gitversionhelper:
_m = re.match(_r,lastTag)
if not _m:
raise RuntimeError("no valid version found in tags")
if VersionStd == "PEP440":
if VersionStd is "PEP440":
ver=_m.group("release").split(".")
ver += ["0"] * (3 - len(ver))
ver[0]=int(ver[0])
@@ -166,14 +263,14 @@ class gitversionhelper:
major, minor, patch = tuple(ver)
pre_count = int(_m.group("pre_n")) if _m.group("pre_n") else 0
post_count = int(_m.group("post_n2")) if _m.group("post_n2") else 0
elif VersionStd == "SemVer":
elif VersionStd is "SemVer":
major, minor, patch = int(_m.group("major")),int(_m.group("minor")),int(_m.group("patch")),(_m.group("prerelease") if _m.group("prerelease") else ""), ""
pre_count = 0
post_count = 0
_v = cls.MetaVersion(major, minor, patch, pre_count, post_count, lastTag)
if ((cls.__OptDict["formated_output"] in kwargs) and (kwargs[cls.__OptDict["formated_output"]]==True)):
if ((cls.__OptDict["formated_output"] in kwargs) and (kwargs[cls.__OptDict["formated_output"]] is True)):
return cls.doFormatVersion(_v,**kwargs)
else:
return _v
@@ -181,7 +278,11 @@ class gitversionhelper:
@classmethod
def doFormatVersion(cls,inputversion:MetaVersion,**kwargs):
"""
output a formated version
output a formated version string
Args:
inputversion: version to be rendered
Return:
formated version string
"""
VersionStd = cls._getVersionStd(**kwargs)
@@ -193,13 +294,13 @@ class gitversionhelper:
patch = inputversion.patch
if (cls.__OptDict["output_format"] in kwargs):
OutputFormat=kwargs[cls.__OptDict["output_format"]]
if OutputFormat == None:
if VersionStd == "PEP440":
if OutputFormat is None:
if VersionStd is "PEP440":
OutputFormat = "{major}.{minor}.{patch}{revpattern}{revcount}"
if post_count > 0:
revpattern=".post"
revcount=f"{post_count}"
elif VersionStd == "SemVer":
elif VersionStd is "SemVer":
OutputFormat = "{major}.{minor}.{patch}{revpattern}{revcount}"
if post_count > 0:
pre_count = pre_count + post_count