From 163b3aff3cc5de23bd5e88ba73dd957034cc206d Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Fri, 20 Nov 2009 07:28:20 -0500 Subject: [PATCH] Added release.py script automating release process --- release.py | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100755 release.py diff --git a/release.py b/release.py new file mode 100755 index 0000000..d064b11 --- /dev/null +++ b/release.py @@ -0,0 +1,159 @@ +#!/usr/bin/python +# +# Copyright (C) 2009 W. Trevor King +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import os +import os.path +import shutil +import string +from subprocess import Popen +import sys + +from update_copyright import Pipe + +def validate_tag(tag): + """ + >>> validate_tag('1.0.0') + >>> validate_tag('A.B.C-r7') + >>> validate_tag('A.B.C r7') + Traceback (most recent call last): + ... + Exception: Invalid character ' ' in tag 'A.B.C r7' + >>> validate_tag('"') + Traceback (most recent call last): + ... + Exception: Invalid character '"' in tag '"' + >>> validate_tag("'") + Traceback (most recent call last): + ... + Exception: Invalid character ''' in tag ''' + """ + for char in tag: + if char in string.digits: + continue + elif char in string.letters: + continue + elif char in ['.','-']: + continue + raise Exception("Invalid character '%s' in tag '%s'" % (char, tag)) + +def bzr_pending_changes(): + """Use `bzr diff`s exit status to detect change: + 1 - changed + 2 - unrepresentable changes + 3 - error + 0 - no change + """ + p = Pipe([['bzr', 'diff']]) + if p.status == 0: + return False + elif p.status in [1,2]: + return True + raise Exception("Error in bzr diff %d\n%s" % (p.status, p.stderrs[-1])) + +def set_release_version(tag): + print "set libbe.version._VERSION = '%s'" % tag + p = Pipe([['sed', '-i', "s/^# *_VERSION *=.*/_VERSION = '%s'/" % tag, + os.path.join('libbe', 'version.py')]]) + assert p.status == 0, p.statuses + +def bzr_commit(commit_message): + print 'commit current status:', commit_message + p = Pipe([['bzr', 'commit', '-m', commit_message]]) + assert p.status == 0, p.statuses + +def bzr_tag(tag): + print 'tag current revision', tag + p = Pipe([['bzr', 'tag', tag]]) + assert p.status == 0, p.statuses + +def bzr_export(target_dir): + print 'export current revision to', target_dir + p = Pipe([['bzr', 'export', target_dir]]) + assert p.status == 0, p.statuses + +def make_version(): + print 'generate libbe/_version.py' + p = Pipe([['make', os.path.join('libbe', '_version.py')]]) + assert p.status == 0, p.statuses + +def make_changelog(filename, tag): + print 'generate ChangeLog file', filename, 'up to tag', tag + p = Popen(['bzr', 'log', '--gnu-changelog', '-n1', '-r', + '..tag:%s' % tag], stdout=file(filename, 'w')) + status = p.wait() + assert status == 0, status + +def set_vcs_name(filename, vcs_name='None'): + """Exported directory is not a bzr repository, so set vcs_name to + something that will work. + vcs_name: new_vcs_name + """ + print 'set_vcs_name in', filename, 'to', vcs_name + p = Pipe([['sed', '-i', "s/^vcs_name:.*/vcs_name: %s/" % vcs_name, + filename]]) + assert p.status == 0, p.statuses + +def create_tarball(tag): + release_name='be-%s' % tag + export_dir = release_name + bzr_export(export_dir) + make_version() + print 'copy libbe/_version.py to %s/libbe/_version.py' % export_dir + shutil.copy(os.path.join('libbe', '_version.py'), + os.path.join(export_dir, 'libbe', '_version.py')) + make_changelog(os.path.join(export_dir, 'ChangeLog'), tag) + set_vcs_name(os.path.join(export_dir, '.be', 'settings')) + tarball_file = '%s.tar.gz' % release_name + print 'create tarball', tarball_file + p = Pipe([['tar', '-czf', tarball_file, export_dir]]) + assert p.status == 0, p.statuses + print 'remove', export_dir + shutil.rmtree(export_dir) + +def test(): + import doctest + doctest.testmod() + +if __name__ == '__main__': + import optparse + usage = """%prog [options] TAG + +Create a bzr tag and a release tarball from the current revision. +For example + %prog 1.0.0 +""" + p = optparse.OptionParser(usage) + p.add_option('--test', dest='test', default=False, + action='store_true', help='Run internal tests and exit') + options,args = p.parse_args() + + if options.test == True: + test() + sys.exit(0) + + assert len(args) == 1, '%d (!= 1) arguments: %s' % (len(args), args) + tag = args[0] + validate_tag(tag) + + if bzr_pending_changes() == True: + print "Handle pending changes before releasing." + sys.exit(1) + set_release_version(tag) + bzr_commit("Bumped to version %s" % tag) + bzr_tag(tag) + create_tarball(tag) -- 2.26.2