Skip to content

Instantly share code, notes, and snippets.

@iddan

iddan/version.py

Last active Oct 30, 2017
Embed
What would you like to do?
Update python setup.py version safely
import ast
import jedi
from os import path
from pipenv.project import Project
from git import Repo
from git.refs.tag import TagReference
from pkg_resources import get_distribution
class Semver:
def __init__(self, string):
major, minor, patch = map(int, string.split('.'))
self.major = major
self.minor = minor
self.patch = patch
def __str__(self):
return '.'.join(map(str, (self.major, self.minor, self.patch)))
def add(self, part, amount):
setattr(self, part, getattr(self, part) + amount)
return self
def is_setup(source, call):
script = jedi.api.Script(source, call.lineno, call.col_offset)
definition = script.goto_definitions()[-1]
return definition.module_name == 'core' and definition.name == 'setup'
def replace_in_line(line, old, new, string):
lines = string.split('\n')
lines[line] = lines[line].replace(old, new)
return '\n'.join(lines)
def get_setup_version_value_node(source):
for node in ast.walk(ast.parse(source)):
if isinstance(node, ast.Call) and is_setup(source, node):
for keyword in node.keywords:
if keyword.arg == 'version':
return keyword.value
project = Project()
def update_setup_file_version(part, setup_path):
with open(setup_path, 'r+') as setup:
source = setup.read()
value = get_setup_version_value_node(source)
old_version = value.s
new_version = str(Semver(old_version).add(part, 1))
setup.seek(0)
setup.write(replace_in_line(value.lineno - 1, old_version, new_version, source))
setup.truncate()
return new_version
# part = 'major' | 'minor' | 'patch'
def version(part):
setup_path = path.join(project.project_directory, 'setup.py')
if not path.exists(setup_path):
raise NotImplementedError('setup.py must exist')
new_version = update_setup_file_version(part, setup_path)
repo = Repo(project.project_directory)
repo.index.add(['setup.py'])
repo.index.commit(f'v{new_version}')
repo.create_tag(f'v{new_version}', ref=repo.active_branch)
return new_version
if __name__ == "__main__":
import sys
new_version = version(sys.argv[1])
print(new_version)
@iddan

This comment has been minimized.

Copy link
Owner Author

@iddan iddan commented Oct 30, 2017

requires pipenv and GitPython installed (pip install pipenv GitPython)
usage: python3 version.py patch | minor | major

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