Skip to content

Commit

Permalink
[setup.py] add 'bump_version' and 'release' setuptools sub-commands
Browse files Browse the repository at this point in the history
  • Loading branch information
Cosimo Lupo committed Apr 13, 2017
1 parent 7ecd1a0 commit 9d0bdad
Showing 1 changed file with 132 additions and 2 deletions.
134 changes: 132 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,132 @@

from __future__ import print_function, division, absolute_import
import sys
from setuptools import setup, find_packages
from setuptools import setup, find_packages, Command
from distutils import log


class bump_version(Command):

description = "increment the package version and commit the changes"

user_options = [
("major", None, "bump the first digit, for incompatible API changes"),
("minor", None, "bump the second digit, for new backward-compatible features"),
("patch", None, "bump the third digit, for bug fixes (default)"),
]

def initialize_options(self):
self.minor = False
self.major = False
self.patch = False

def finalize_options(self):
part = None
for attr in ("major", "minor", "patch"):
if getattr(self, attr, False):
if part is None:
part = attr
else:
from distutils.errors import DistutilsOptionError
raise DistutilsOptionError(
"version part options are mutually exclusive")
self.part = part or "patch"

def bumpversion(self, part, tag=False, message=None):
""" Run bumpversion.main() with the specified arguments, and return the
new computed version string.
"""
import bumpversion

args = (
(['--verbose'] if self.verbose > 1 else []) +
(['--tag'] if tag else ['--no-tag']) +
(['--message', message] if message is not None else []) +
[part]
)
log.debug(
"$ bumpversion %s" % " ".join(a.replace(" ", "\\ ") for a in args))

bumpversion.main(args)

def run(self):
log.info("bumping '%s' version" % self.part)
self.bumpversion(self.part)


class release(bump_version):
"""Drop the developmental release '.devN' suffix from the package version,
open the default text $EDITOR to write release notes, commit the changes
and generate a git tag.
Release notes can also be set with the -m/--message option, or by reading
from standard input.
"""

description = "tag a new release"

user_options = [
("message=", 'm', "message containing the release notes"),
]

def initialize_options(self):
self.message = None

def finalize_options(self):
import re

current_version = self.distribution.metadata.get_version()
if not re.search(r"\.dev[0-9]+", current_version):
from distutils.errors import DistutilsSetupError
raise DistutilsSetupError(
"current version (%s) has no '.devN' suffix.\n "
"Run 'setup.py bump_version', or use any of "
"--major, --minor, --patch options" % current_version)

message = self.message
if message is None:
if sys.stdin.isatty():
# stdin is interactive, use editor to write release notes
message = self.edit_release_notes()
else:
# read release notes from stdin pipe
message = sys.stdin.read()

if not message.strip():
from distutils.errors import DistutilsSetupError
raise DistutilsSetupError("release notes message is empty")

self.message = "Release {new_version}\n\n%s" % (message)

@staticmethod
def edit_release_notes():
"""Use the default text $EDITOR to write release notes.
If $EDITOR is not set, use 'nano'."""
from tempfile import mkstemp
import os
import shlex
import subprocess

text_editor = shlex.split(os.environ.get('EDITOR', 'nano'))

fd, tmp = mkstemp(prefix='bumpversion-')
try:
os.close(fd)
with open(tmp, 'w') as f:
f.write("\n\n# Write release notes.\n"
"# Lines starting with '#' will be ignored.")
subprocess.check_call(text_editor + [tmp])
with open(tmp, 'r') as f:
changes = "".join(
l for l in f.readlines() if not l.startswith('#'))
finally:
os.remove(tmp)
return changes

def run(self):
log.info("stripping developmental release suffix")
# drop '.dev0' suffix, commit with given message and create git tag
self.bumpversion("release", tag=True, message=self.message)


needs_pytest = {'pytest', 'test'}.intersection(sys.argv)
Expand All @@ -27,7 +152,8 @@
packages=find_packages("Lib"),
include_package_data=True,
license="MIT",
setup_requires=pytest_runner + wheel,
setup_requires=pytest_runner + wheel + (
['bumpversion'] if {'release', 'bump_version'}.intersection(sys.argv) else []),
tests_require=[
'pytest>=2.8',
],
Expand All @@ -38,6 +164,10 @@
"cu2qu>=1.1.1",
"compreffor>=0.4.4",
],
cmdclass={
"release": release,
"bump_version": bump_version,
},
classifiers=[
'Development Status :: 4 - Beta',
"Environment :: Console",
Expand Down

0 comments on commit 9d0bdad

Please sign in to comment.