Skip to content

Instantly share code, notes, and snippets.

@mbrgm
Created January 26, 2014 17:42
Show Gist options
  • Save mbrgm/8636481 to your computer and use it in GitHub Desktop.
Save mbrgm/8636481 to your computer and use it in GitHub Desktop.
Offers a way to get the current version in a git repository by finding the latest version tag and counting the number of commits since then, if necessary. The version tags are required to begin with a leading 'v'. The version format is <major>.<minor>.<patch>[-<prerelease-type>.<prerelease-number>][+<commit-number>].
#!/usr/bin/env python
import sys
import os
import re
import plistlib
from subprocess import check_output
class Version:
_REGEX = re.compile(
'^v?(?P<major>[0-9]+)'
'\.(?P<minor>[0-9]+)'
'\.(?P<patch>[0-9]+)'
'(\-(?P<release_type>(alpha|beta|rc))\.'
'(?P<prerelease_number>[0-9]+))?'
'(\+(?P<commit_number>[0-9]+))?$')
RELEASE_TYPES = ['alpha', 'beta', 'rc', 'public']
def __init__(self,
major,
minor,
patch,
release_type='public',
prerelease_number=None,
commit_number=None):
self.major = int(major)
self.minor = int(minor)
self.patch = int(patch)
if release_type:
self.release_type = release_type
else:
self.release_type = 'public'
if prerelease_number and self.release_type != 'public':
self.prerelease_number = int(prerelease_number)
else:
self.prerelease_number = None
if commit_number:
self.commit_number = int(commit_number)
else:
try:
self.commit_number = self.get_commit_number()
except:
self.commit_number = None
def get_commit_number(self):
# Get commits since tagged commit
tag = self.get_tag()
devnull = open(os.devnull, 'w')
output = check_output(['git',
'rev-list',
tag + '..HEAD'], stderr=devnull).strip()
output_lines = output.split('\n')
commits = filter(lambda x: x, output_lines)
return len(commits)
def get_tag(self):
return 'v' + self.get_version_string_without_commit()
@classmethod
def from_string(cls, string):
# Parse version components using regex
match = cls._REGEX.match(string.strip())
v = match.groupdict()
version = Version(major=v['major'],
minor=v['minor'],
patch=v['patch'],
release_type=v['release_type'],
prerelease_number=v['prerelease_number'])
return version
def get_version_string_without_commit(self):
# Build version string
version_string = "%d.%d.%d" % (self.major,
self.minor,
self.patch)
if self.release_type != 'public':
version_string += "-%s.%d" % (self.release_type,
self.prerelease_number)
return version_string
def get_version_string(self):
version_string = self.get_version_string_without_commit()
if self.commit_number:
version_string += "+%d" % self.commit_number
return version_string
def __repr__(self):
return "<Version %s>" % self.get_version_string()
def __eq__(self, other):
self_type_value = \
self.RELEASE_TYPES.index(self.release_type)
other_type_value = \
self.RELEASE_TYPES.index(other.release_type)
return self.major == other.major \
and self.minor == other.minor \
and self.patch == other.patch \
and self_type_value == other_type_value \
and self.prerelease_number == other.prerelease_number \
and self.commit_number == other.commit_number
def __ne__(self, other):
return not self == other
def __gt__(self, other):
# Compare main version part
if self.major > other.major:
return True
if self.minor > other.minor:
return True
if self.patch > other.patch:
return True
# Get ordinal value for prerelease type
self_type_value = \
self.RELEASE_TYPES.index(self.release_type)
other_type_value = \
self.RELEASE_TYPES.index(other.release_type)
# Compare prerelease part
if self_type_value > other_type_value:
return True
if self.prerelease_number > other.prerelease_number:
return True
# Compare commit number
if self.commit_number > other.commit_number:
return True
return False
def __lt__(self, other):
return not self > other
def __ge__(self, other):
return not self < other
def __le__(self, other):
return not self > other
def get_latest_version_from_git():
# Get all version tags
devnull = open(os.devnull, 'w')
output = check_output(['git',
'tag',
'--list',
'v*'], stderr=devnull)
output_lines = output.split('\n')
version_tags = filter(lambda x: x, output_lines)
# Create versions for all version tags
versions = map(lambda x: Version.from_string(x), version_tags)
# Pick latest version
versions.sort()
latest_version = versions[-1]
return latest_version
# Parse arguments
command = sys.argv[1]
# Execute given command
if command == 'show':
latest_version = get_latest_version_from_git()
print latest_version.get_version_string().strip()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment