Browse files

Add release script

  • Loading branch information...
mattupstate committed Oct 11, 2012
1 parent 2d7f9f2 commit 4ec0b8232de519836f8153b1d75788c47a6a3ac1
Showing with 189 additions and 0 deletions.
  1. +189 −0 scripts/
@@ -0,0 +1,189 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
Helper script that performs a release. Does pretty much everything
automatically for us.
:copyright: (c) 2011 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
import sys
import os
import re
from datetime import datetime, date
from subprocess import Popen, PIPE
_date_clean_re = re.compile(r'(\d+)(st|nd|rd|th)')
def installed_libraries():
return Popen(['pip', 'freeze'], stdout=PIPE).communicate()[0]
def has_library_installed(library):
return library + '==' in installed_libraries()
def parse_changelog():
with open('CHANGES') as f:
lineiter = iter(f)
for line in lineiter:
match ='^Version\s+(.*)', line.strip())
if match is None:
version =
if'-') != len(line.strip()):
fail('Invalid hyphen count below version line: %s', line.strip())
while 1:
released =
if released:
match ='Released (\w+\s+\d+\w+\s+\d+)', released)
if match is None:
fail('Could not find release date in version %s' % version)
datestr = parse_date(
return version, datestr
def bump_version(version):
parts = map(int, version.split('.'))
except ValueError:
fail('Current version is not numeric')
parts[-1] += 1
return '.'.join(map(str, parts))
def parse_date(string):
string = _date_clean_re.sub(r'\1', string)
return datetime.strptime(string, '%B %d %Y')
def set_filename_version(filename, version_number, pattern):
changed = []
def inject_version(match):
before, old, after = match.groups()
return before + version_number + after
with open(filename) as f:
contents = re.sub(r"^(\s*%s\s*=\s*')(.+?)(')(?sm)" % pattern,
if not changed:
fail('Could not find %s in %s', pattern, filename)
with open(filename, 'w') as f:
def set_init_version(version):
info('Setting version to %s', version)
set_filename_version('flask_social/', version, '__version__')
def set_setup_version(version):
info('Setting version to %s', version)
set_filename_version('', version, 'version')
def set_docs_version(version):
info('Setting docs/ version to %s', version)
set_filename_version('docs/', version, 'version')
def build_and_upload():
Popen([sys.executable, '', 'sdist', 'build_sphinx', 'upload', 'upload_sphinx']).wait()
def fail(message, *args):
print >> sys.stderr, 'Error:', message % args
def info(message, *args):
print >> sys.stderr, message % args
def get_git_tags():
return set(Popen(['git', 'tag'], stdout=PIPE).communicate()[0].splitlines())
def git_is_clean():
return Popen(['git', 'diff', '--quiet']).wait() == 0
def make_git_commit(message, *args):
message = message % args
Popen(['git', 'commit', '-am', message]).wait()
def make_git_tag(tag):
info('Tagging "%s"', tag)
Popen(['git', 'tag', '-a', tag, '-m', '%s release' % tag]).wait()
Popen(['git', 'push', '--tags']).wait()
def update_version(version):
for f in [set_init_version, set_setup_version, set_docs_version]:
def get_branches():
return set(Popen(['git', 'branch'], stdout=PIPE).communicate()[0].splitlines())
def branch_is(branch):
return '* ' + branch in get_branches()
def main():
os.chdir(os.path.join(os.path.dirname(__file__), '..'))
rv = parse_changelog()
if rv is None:
fail('Could not parse changelog')
version, release_date = rv
tags = get_git_tags()
for lib in ['Sphinx', 'Sphinx-PyPI-upload']:
if not has_library_installed(lib):
fail('Build requires that %s be installed', lib)
if version in tags:
fail('Version "%s" is already tagged', version)
if !=
fail('Release date is not today')
if not branch_is('master'):
fail('You are not on the master branch')
if not git_is_clean():
fail('You have uncommitted changes in git')
info('Releasing %s (release date %s)',
version, release_date.strftime('%d/%m/%Y'))
make_git_commit('Bump version number to %s', version)
if __name__ == '__main__':

0 comments on commit 4ec0b82

Please sign in to comment.