Last active
October 30, 2017 20:57
-
-
Save iddan/22bbb835f7a862a314f995f5d66674eb to your computer and use it in GitHub Desktop.
Update python setup.py version safely
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
requires pipenv and GitPython installed (
pip install pipenv GitPython
)usage:
python3 version.py patch | minor | major