diff --git a/dulwich/contrib/release_robot.py b/dulwich/contrib/release_robot.py index eb00aa40..6209f3a2 100644 --- a/dulwich/contrib/release_robot.py +++ b/dulwich/contrib/release_robot.py @@ -1,100 +1,101 @@ -""" +"""Determine last version string from tags. + 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_current_version __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. + """Get list of 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 + """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