diff --git a/dulwich/contrib/release_robot.py b/dulwich/contrib/release_robot.py index af600e71..eb00aa40 100644 --- a/dulwich/contrib/release_robot.py +++ b/dulwich/contrib/release_robot.py @@ -1,59 +1,100 @@ """ Alternate to `Versioneer `_ using `Dulwich `_ to sort tags by time from newest to oldest. Import this module into the package ``__init__.py`` and then set ``__version__`` as follows:: - from dulwich.contrib.release_robot import get_recent_tags + from dulwich.contrib.release_robot import get_current_version - __version__ = get_recent_tags()[0][0][1:] + __version__ = get_current_version() # other dunder classes like __author__, etc. This example assumes the tags have a leading "v" like "v0.3", and that the ``.git`` folder is in the project folder that containts the package folder. """ from dulwich.repo import Repo import time import datetime import os +import re # CONSTANTS DIRNAME = os.path.abspath(os.path.dirname(__file__)) PROJDIR = os.path.dirname(DIRNAME) +PATTERN = '[ a-zA-Z_\-]*([\d\.]+[\-\w\.]*)' def get_recent_tags(projdir=PROJDIR): """ Get list of recent tags in order from newest to oldest and their datetimes. :param projdir: path to ``.git`` :returns: list of (tag, [datetime, commit, author]) sorted from new to old """ project = Repo(projdir) # dulwich repository object refs = project.get_refs() # dictionary of refs and their SHA-1 values tags = {} # empty dictionary to hold tags, commits and datetimes # iterate over refs in repository for key, value in refs.iteritems(): obj = project.get_object(value) # dulwich object from SHA-1 # check if object is tag if obj.type_name != 'tag': # skip ref if not a tag continue # strip the leading text from "refs/tag/" to get "tag name" _, tag = key.rsplit('/', 1) # check if tag object is commit, altho it should always be true if obj.object[0].type_name == 'commit': commit = project.get_object(obj.object[1]) # commit object # get tag commit datetime, but dulwich returns seconds since # beginning of epoch, so use Python time module to convert it to # timetuple then convert to datetime tags[tag] = [ datetime.datetime(*time.gmtime(commit.commit_time)[:6]), commit.id, commit.author ] # return list of tags sorted by their datetimes from newest to oldest return sorted(tags.iteritems(), key=lambda tag: tag[1][0], reverse=True) + + +def get_current_version(pattern=PATTERN, projdir=PROJDIR, logger=None): + """ + Return the most recent tag, using an options regular expression pattern. The + default pattern will strip any characters preceding the first semantic + version. *EG*: "Release-0.2.1-rc.1" will be come "0.2.1-rc.1". If no match + is found, then the most recent tag is return without modification. + + :param pattern: regular expression pattern with group that matches version + :param projdir: path to ``.git`` + :param logger: a Python logging instance to capture exception + :returns: tag matching first group in regular expression pattern + """ + tags = get_recent_tags(projdir) + try: + tag = tags[0][0] + except IndexError: + return + m = re.match(pattern, tag) + try: + current_version = m.group(1) + except (IndexError, AttributeError) as err: + if logger: + logger.exception(err) + return tag + return current_version + + +def test_tag_pattern(): + test_cases = { + '0.3': '0.3', 'v0.3': '0.3', 'release0.3': '0.3', 'Release-0.3': '0.3', + 'v0.3rc1': '0.3rc1', 'v0.3-rc1': '0.3-rc1', 'v0.3-rc.1': '0.3-rc.1', + 'version 0.3': '0.3', 'version_0.3_rc_1': '0.3_rc_1', 'v1': '1', + '0.3rc1': '0.3rc1' + } + for tc, version in test_cases.iteritems(): + m = re.match(PATTERN, tc) + assert m.group(1) == version