add commit class

This commit is contained in:
cclecle
2023-03-19 09:52:42 +00:00
parent 38cde9d700
commit cefa964a3a
3 changed files with 309 additions and 11 deletions

1
Jenkinsfile vendored
View File

@@ -181,7 +181,6 @@ pipeline {
sh("rm -Rf ~/_gitrepo || true")
//sh(". ~/BUILD_ENV/bin/activate && python -m copier --vcs-ref HEAD --prereleases --defaults ./ ~/_gitrepo")
sh(script: """#!/bin/sh -
|. ~/BUILD_ENV/bin/activate
|exec python - << '__EOWRAPPER__'

View File

@@ -5,7 +5,6 @@
#
# 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 project try to help doing handy operations with git when
dealing with project versioning and tags on python project -
@@ -13,6 +12,7 @@ at leat for project using PEP440 or SemVer standards.
One requirement is to keep it compact and to not cover too much fancy features.
This is the reason why it is one single file with nested classes.
=> Design is on-purpose poorly expandable to keep the scope light.
This library is maid for repository using tag as version.
@@ -23,8 +23,7 @@ This module is the main project file, containing all the code.
Read the read me for more information.
Check the unittest s for usage samples.
Note:
Other Parameters are **kwargs
Note: _Other Parameters_ are **kwargs
"""
from __future__ import annotations
@@ -37,7 +36,7 @@ import logging
from packaging.version import VERSION_PATTERN as packaging_VERSION_PATTERN
def _exec(cmd: str, root: str | os.PathLike | None = None) -> list[str]:
def _exec(cmd: str, root: str | os.PathLike | None = None, raw:bool = False) -> list[str]:
"""
helper function to handle system cmd execution
Args:
@@ -47,13 +46,16 @@ def _exec(cmd: str, root: str | os.PathLike | None = None) -> list[str]:
a list of command's return lines
"""
p = subprocess.run(cmd.split(), text=True, cwd=root, capture_output=True, check=False, timeout=2)
p = subprocess.run(cmd, text=True, cwd=root, capture_output=True, check=False, timeout=2,shell=True)
if re.search("not a git repository",p.stderr):
raise gitversionhelper.repository.notAGitRepository()
if re.search("fatal:",p.stderr): #pragma: nocover
raise gitversionhelper.unknownGITFatalError(p.stderr)
if int(p.returncode) < 0: #pragma: nocover
raise gitversionhelper.unknownGITError(p.stderr)
if raw:
return p.stdout
lines = p.stdout.splitlines()
return [line.rstrip() for line in lines if line.rstrip()]
@@ -108,6 +110,103 @@ class gitversionhelper: # pylint: disable=too-few-public-methods
True if it is dirty
"""
return bool(_exec("git status --short"))
class commit:
"""
class containing methods focusing on commits
"""
__OptDict = {"same_branch": "same_branch",
"merged_output":"merged_output"}
class commitException(gitversionhelperException):
"""
generic commit exception
"""
class commitNotFound(commitException):
"""
tag not found exception
"""
@classmethod
def getMessagesSinceTag(cls,tag:str,**kwargs) -> str:
"""
retrieve a commits message history from repository
from LastCommit to the given tag
Keyword Arguments:
merged_output: output one single merged string
same_branch(bool): force searching only in the same branch
Returns:
the commit message
"""
current_commit_id=cls.getLast(**kwargs)
tag_commit_id=cls.getFromTag(tag,**kwargs)
if ((cls.__OptDict["same_branch"] in kwargs) and (kwargs[cls.__OptDict["same_branch"]] is True)):
commits = _exec(f"git rev-list --first-parent --ancestry-path {tag_commit_id}..{current_commit_id}")
else:
commits = _exec(f"git rev-list --ancestry-path {tag_commit_id}..{current_commit_id}")
result=[]
for commit in commits:
result.append(cls.getMessage(commit,**kwargs))
if ((cls.__OptDict["merged_output"] in kwargs) and (kwargs[cls.__OptDict["merged_output"]] is True)):
print("JOIN")
return os.linesep.join(result)
return result
@classmethod
def getMessage(cls, id:str, **kwargs) -> str:
"""
retrieve a commit message from repository
Args:
id: id of the commit
Returns:
the commit message
"""
try:
res=_exec(f"git log -z --pretty=tformat:%B%-C() -n 1 {id}",None,True).rstrip('\x00')
except gitversionhelper.unknownGITFatalError as _e:
raise cls.commitNotFound("no commit found in commit history") from _e
return res.replace('\r\n','\n').replace('\n','\r\n')
@classmethod
def getFromTag(cls,tag:str,**kwargs) -> str:
"""
retrieve a commit from repository associated to a tag
Args:
tag: tag of the commit
Returns:
the commit Id
"""
try:
res=_exec(f"git rev-list -n 1 {tag}")
except gitversionhelper.unknownGITFatalError as _e:
raise cls.commitNotFound("no commit found in commit history") from _e
if len(res)==0:
raise cls.commitNotFound("no commit found in commit history")
return res[0]
@classmethod
def getLast(cls,**kwargs) -> str:
"""
retrieve last commit from repository
Keyword Arguments:
same_branch(bool): force searching only in the same branch
Returns:
the commit Id
"""
if ((cls.__OptDict["same_branch"] in kwargs) and (kwargs[cls.__OptDict["same_branch"]] is True)):
try:
res = _exec("git rev-parse HEAD")
except gitversionhelper.unknownGITFatalError as _e:
raise cls.commitNotFound("no commit found in commit history") from _e
else:
res = _exec("git for-each-ref --sort=-committerdate refs/heads/ --count 1 --format=%(objectname)")
if len(res)==0:
raise cls.commitNotFound("no commit found in commit history")
return res[0]
class tag:
"""
@@ -132,7 +231,7 @@ class gitversionhelper: # pylint: disable=too-few-public-methods
"""
@classmethod
def getTags(cls,sort:str = "taggerdate",**kwargs) -> list[str]:
def getTags(cls,sort:str = "taggerdate",**kwargs) -> list[str|None]:
"""
retrieve all tags from a repository
Args:
@@ -457,8 +556,8 @@ class gitversionhelper: # pylint: disable=too-few-public-methods
VersionStd = "PEP440"
if not bFound :
raise gitversionhelper.version.noValidVersion("no valid version found in tags")
raise gitversionhelper.version.noValidVersion("no valid version found in tags")
if pre_count > 0 and post_count > 0:
raise cls.PreAndPostVersionUnsupported("can not parse a version with both pre" \
" and post release number.")

View File

@@ -13,6 +13,8 @@ import os
import pathlib
import re
import copy
import time
import subprocess
print(__name__)
print(__package__)
@@ -507,8 +509,7 @@ class Test_gitversionhelper(unittest.TestCase):
self.assertEqual(_v.major,0)
self.assertEqual(_v.minor,1)
self.assertEqual(_v.patch,0)
def test_nominal__version___AUTO_bump_commits(self):
with open("demofile.txt", "w+t") as tmpFile:
tmpFile.write("testvalue")
@@ -1114,6 +1115,205 @@ class Test_gitversionhelper(unittest.TestCase):
self.assertEqual(_v.minor,1)
self.assertEqual(_v.patch,3)
def test_nominal__commit_getLast(self):
# sleeps are needed because commit date have a 1-sec accuracy :-/
with open("demofile.txt", "w+t") as tmpFile:
tmpFile.write("testvalue")
os.system("git add .")
os.system("git commit -m \"commit\"")
time.sleep(1)
initial_commit = pygitversionhelper.gitversionhelper.commit.getLast()
with open("demofile.txt", "w+t") as tmpFile:
tmpFile.write("testvalue2")
os.system("git add .")
os.system("git commit -m \"commit\"")
time.sleep(1)
second_commit = pygitversionhelper.gitversionhelper.commit.getLast()
self.assertNotEqual(initial_commit,second_commit)
with open("demofile.txt", "w+t") as tmpFile:
tmpFile.write("testvalue3")
os.system("git add .")
os.system("git commit -m \"commit\"")
time.sleep(1)
third_commit = pygitversionhelper.gitversionhelper.commit.getLast()
self.assertNotEqual(initial_commit,third_commit)
self.assertNotEqual(second_commit,third_commit)
os.system("git checkout -b dev")
with open("demofile.txt", "w+t") as tmpFile:
tmpFile.write("testvalue4")
os.system("git add .")
os.system("git commit -m \"commit\"")
time.sleep(1)
fourth_commit = pygitversionhelper.gitversionhelper.commit.getLast()
self.assertNotEqual(initial_commit,fourth_commit)
self.assertNotEqual(second_commit,fourth_commit)
self.assertNotEqual(third_commit,fourth_commit)
os.system("git switch master")
fourth2_commit = pygitversionhelper.gitversionhelper.commit.getLast()
self.assertEqual(fourth2_commit,fourth_commit)
fourth3_commit = pygitversionhelper.gitversionhelper.commit.getLast(same_branch=True)
self.assertNotEqual(fourth3_commit,fourth_commit)
self.assertEqual(fourth3_commit,third_commit)
with open("demofile.txt", "w+t") as tmpFile:
tmpFile.write("testvalue5")
os.system("git add .")
os.system("git commit -m \"commit\"")
time.sleep(1)
fifth_commit = pygitversionhelper.gitversionhelper.commit.getLast()
self.assertNotEqual(fifth_commit,fourth3_commit)
os.system("git switch dev")
fifth2_commit = pygitversionhelper.gitversionhelper.commit.getLast()
self.assertEqual(fifth2_commit,fifth_commit)
fifth2_commit = pygitversionhelper.gitversionhelper.commit.getLast(same_branch=True)
self.assertEqual(fifth2_commit,fourth_commit)
def test_defect__commit_notfound(self):
with self.assertRaises(pygitversionhelper.gitversionhelper.commit.commitNotFound) :
pygitversionhelper.gitversionhelper.commit.getLast()
with self.assertRaises(pygitversionhelper.gitversionhelper.commit.commitNotFound) :
pygitversionhelper.gitversionhelper.commit.getLast(same_branch=True)
def test_nominal__commit_getFromTag(self):
with open("demofile.txt", "w+t") as tmpFile:
tmpFile.write("testvalue")
os.system("git add .")
os.system("git commit -m \"commit\"")
initial_commit = pygitversionhelper.gitversionhelper.commit.getLast()
with open("demofile.txt", "w+t") as tmpFile:
tmpFile.write("testvalue2")
os.system("git add .")
os.system("git commit -m \"commit2\"")
os.system(f"git tag TAG")
second_commit = pygitversionhelper.gitversionhelper.commit.getLast()
self.assertNotEqual(second_commit,initial_commit)
second_commit2 = pygitversionhelper.gitversionhelper.commit.getFromTag("TAG")
self.assertEqual(second_commit,second_commit2)
self.assertNotEqual(second_commit2,initial_commit)
def test_defect__commit_notfound2(self):
with self.assertRaises(pygitversionhelper.gitversionhelper.commit.commitNotFound) :
pygitversionhelper.gitversionhelper.commit.getFromTag("TAG")
with open("demofile.txt", "w+t") as tmpFile:
tmpFile.write("testvalue")
os.system("git add .")
os.system("git commit -m \"commit\"")
with self.assertRaises(pygitversionhelper.gitversionhelper.commit.commitNotFound) :
pygitversionhelper.gitversionhelper.commit.getFromTag("TAG")
os.system(f"git tag OTHER_TAG")
with self.assertRaises(pygitversionhelper.gitversionhelper.commit.commitNotFound) :
pygitversionhelper.gitversionhelper.commit.getFromTag("TAG")
def test_nominal__commit_getMessage(self):
commit_message="AAAABBB CCCCDDDD"
with open("demofile.txt", "w+t") as tmpFile:
tmpFile.write("testvalue")
os.system("git add .")
os.system(f"git commit -m \"{commit_message}\"")
commit = pygitversionhelper.gitversionhelper.commit.getLast()
message = pygitversionhelper.gitversionhelper.commit.getMessage(commit)
self.assertEqual(message,commit_message)
def test_nominal__commit_getMessage2(self):
commit_message="""AAAABBB
CCCCDDDD
-f dfsds dfsdfs $"""
with open("demofile.txt", "w+t") as tmpFile:
tmpFile.write("testvalue")
os.system("git add .")
cmd = "git commit -m".split()
cmd.append(commit_message)
subprocess.run(cmd,text=True,check=True)
commit = pygitversionhelper.gitversionhelper.commit.getLast()
message = pygitversionhelper.gitversionhelper.commit.getMessage(commit)
print(message)
self.assertEqual(message,commit_message)
def test_nominal__commit_getMessagesSinceLastTag(self):
commit_message1="1.1 update this"+ os.linesep+\
"1.1 fix that" + os.linesep+\
"1.1 test"
with open("demofile.txt", "w+t") as tmpFile:
tmpFile.write("testvalue")
os.system("git add .")
cmd = "git commit -m".split()
cmd.append(commit_message1)
subprocess.run(cmd,text=True,check=True)
os.system(f"git tag 0.1.1")
commit_message2="2.1 update this"+ os.linesep+\
"2.1 fix that" + os.linesep+\
"2.1 test"
with open("demofile.txt", "w+t") as tmpFile:
tmpFile.write("testvalue2")
os.system("git add .")
cmd = "git commit -m".split()
cmd.append(commit_message2)
subprocess.run(cmd,text=True,check=True)
commit_message3="3.1 update this"+ os.linesep+\
"3.1 fix that" + os.linesep+\
"3.1 test"
with open("demofile.txt", "w+t") as tmpFile:
tmpFile.write("testvalue3")
os.system("git add .")
cmd = "git commit -m".split()
cmd.append(commit_message3)
subprocess.run(cmd,text=True,check=True)
commit_message4="4.1 update this" + os.linesep+\
"4.1 fix that" + os.linesep+\
"4.1 test"
with open("demofile.txt", "w+t") as tmpFile:
tmpFile.write("testvalue4")
os.system("git add .")
cmd = "git commit -m".split()
cmd.append(commit_message4)
subprocess.run(cmd,text=True,check=True)
res = pygitversionhelper.gitversionhelper.commit.getMessagesSinceTag("0.1.1")
self.assertEqual( [commit_message4,commit_message3,commit_message2],res)
res = pygitversionhelper.gitversionhelper.commit.getMessagesSinceTag("0.1.1",merged_output=True)
self.assertEqual( os.linesep.join([commit_message4,commit_message3,commit_message2]),res)
def tearDown(self):
os.chdir("/")