Skip to content

Instantly share code, notes, and snippets.

@aolwas
Forked from mina86/version.py
Last active October 28, 2019 15:18
Show Gist options
  • Save aolwas/30c5a32c7ecb253aaf6eaa17a27fbb4e to your computer and use it in GitHub Desktop.
Save aolwas/30c5a32c7ecb253aaf6eaa17a27fbb4e to your computer and use it in GitHub Desktop.
Extract a setuptools version from the git repository's tags.
# -*- coding: utf-8 -*-
"""Calculates the current version number.
Uses output of “git describe --long --tags --always --dirty='-dev-$(date +%s)'”
interpreted as <version>-<commits>-<sha>-<dirty>
if commits != 0 and not dirty, return version else return full output.
If "git describe" fails (when install via package, copied src, etc), version is
read from RELEASE-VERSION file.
To use this script, simply import it your setup.py file, and use the results
of get_version() as your package version:
import version
setup(
version=version.get_version(),
.
.
.
)
This will automatically update the RELEASE-VERSION file. The RELEASE-VERSION
file should *not* be checked into git but it *should* be included in sdist
tarballs (as should version.py file). To do this, run:
echo include RELEASE-VERSION version.py >>MANIFEST.in
echo RELEASE-VERSION >>.gitignore
With that setup, a new release can be labelled by simply invoking:
git tag -s v1.0
"""
__author__ = ('Douglas Creager <[email protected]>',
'Michal Nazarewicz <[email protected]>',
'Maxime Cottret <[email protected]>', )
__license__ = 'This file is placed into the public domain.'
__maintainer__ = 'Maxime Cottret'
__email__ = '[email protected]'
__all__ = ('get_version')
import os
import re
import subprocess
import sys
_RELEASE_VERSION_FILE = os.path.dirname(__file__) + '/RELEASE-VERSION'
_RE_GIT_DESCRIBE = r"v?(?:(?P<version>[\d.]+)(?P<pre>-\w+[\d.]*)?-(?P<commits>\d+)-g)?(?P<sha>[0-9a-f]{7})(?P<dirty>.\d+)?"
def read_git_version():
try:
output = subprocess.run('git describe --long --tags --always --dirty=".$(date +%s)"', shell=True, check=True, stdout=subprocess.PIPE).stdout
ver = output.splitlines()[0].strip().decode()
except subprocess.CalledProcessError as e:
return None
if not ver:
return None
m = re.search(_RE_GIT_DESCRIBE, ver)
if not m:
sys.stderr.write('version: git description (%s) is invalid, '
'ignoring\n' % ver)
return None
version = m.group('version') or '0.0.0'
if m.group('pre'):
version += m.group('pre')
if not m.group('version') or (m.group('commits') and int(m.group('commits')) != 0) or m.group('dirty'):
version = "{}+{}{}{}".format(version,
m.group('sha'),
'.{}'.format(m.group('commits')) if m.group('commits') else '',
m.group('dirty') or '')
return version
def read_release_version():
try:
fd = open(_RELEASE_VERSION_FILE)
try:
ver = fd.readline().strip()
finally:
fd.close()
return ver
except:
return None
def write_release_version(version):
fd = open(_RELEASE_VERSION_FILE, 'w')
fd.write('%s\n' % version)
fd.close()
def get_version():
release_version = read_release_version()
version = read_git_version() or release_version
if not version:
raise ValueError('Cannot find the version number')
if version != release_version:
write_release_version(version)
return version
if __name__ == '__main__':
print(get_version())
@aolwas
Copy link
Author

aolwas commented Oct 28, 2019

This version builds both PEP-440 and semver2 compatible version string

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment