basic release script; needs work, but probably good enough for the current

2008-02-03  Thomas Thurman  <tthurman@gnome.org>

        * tools/release-wrangler.py: basic release script; needs work,
        but probably good enough for the current unstable release


svn path=/trunk/; revision=3541
This commit is contained in:
Thomas Thurman 2008-02-03 21:47:09 +00:00 committed by Thomas James Alexander Thurman
parent a660fd3805
commit 836a1f7b08
2 changed files with 230 additions and 161 deletions

View File

@ -1,3 +1,8 @@
2008-02-03 Thomas Thurman <tthurman@gnome.org>
* tools/release-wrangler.py: basic release script; needs work,
but probably good enough for the current unstable release
2008-02-02 Thomas Thurman <tthurman@gnome.org> 2008-02-02 Thomas Thurman <tthurman@gnome.org>
* src/Makefile.am: core.h is in include, not core. (Last one, I * src/Makefile.am: core.h is in include, not core. (Last one, I

View File

@ -21,42 +21,61 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA. # 02111-1307, USA.
# This script doesn't do all the work yet, but it will soon.
import os import os
import posixpath import posixpath
import re import re
import sys import sys
import commands import commands
import time
# First step is always to get up to date. def report_error(message):
print message
sys.exit(255)
def get_up_to_date():
"First step is always to get up to date."
os.system("svn up") os.system("svn up")
################################################################ # yes, I know this is MY username. I will come back and fix it
# later, but for now there is a lot else to do. FIXME
your_username = 'Thomas Thurman <tthurman@gnome.org>'
# Are we up to date now? def changelog_and_checkin(filename, message):
changelog = open('ChangeLog.tmp', 'w')
changelog.write('%s %s\n\n * %s: %s\n\n' % (
time.strftime('%Y-%m-%d',time.gmtime()),
your_username,
filename,
message))
for line in open('ChangeLog').readlines():
changelog.write(line)
changelog.close()
os.rename('ChangeLog.tmp', 'ChangeLog')
os.system('svn commit -m \\"%s\\"' % (message.replace('"','\\"')))
def check_we_are_up_to_date():
changed = [] changed = []
for line in commands.getoutput('/usr/bin/svn status').split('\n'): for line in commands.getoutput('/usr/bin/svn status').split('\n'):
if line!='' and (line[0]=='C' or line[0]=='M'): if line!='' and (line[0]=='C' or line[0]=='M'):
changed.append(line[1:].lstrip()) changed.append(line[1:].lstrip())
if changed: if changed:
print 'These files are out of date; I can\'t continue until you fix them.' report_error('These files are out of date; I can\'t continue until you fix them: ' + \
print ', '.join(changed) ', '.join(changed))
sys.exit(255)
################################################################
def version_numbers():
# FIXME: This is all very metacity-specific. Compare fusa, etc # FIXME: This is all very metacity-specific. Compare fusa, etc
# """Okay, read through configure.in and find who and where we are.
# Okay, read through configure.in and find who and where we are.
# We also try to figure out where the next micro version number
# We also try to figure out where the next micro version number will be; some programs (e.g. Metacity) use a custom numbering
# will be; some programs (e.g. Metacity) use a custom numbering scheme, and if they have a list of numbers on the line before the
# scheme, and if they have a list of numbers on the line before the micro version then that will be used. Otherwise we will just
# micro version then that will be used. Otherwise we will just increment."""
# increment.
version = {} version = {}
previous_line = '' previous_line = ''
for line in file("configure.in").readlines(): for line in file("configure.in").readlines():
@ -81,35 +100,32 @@ for line in file("configure.in").readlines():
try: try:
version['micro_next'] = versions[versions.index(version_value)+1] version['micro_next'] = versions[versions.index(version_value)+1]
except: except:
print "You gave a list of micro version numbers, but we've used them up!" report_error("You gave a list of micro version numbers, but we've used them up!")
sys.exit(255)
else: else:
print "You gave a list of micro version numbers, but the current one wasn't in it!" report_error("You gave a list of micro version numbers, but the current one wasn't in it! Current is %s and your list is %s" % (
print "Current is ",version_value `version_value`, `versions`))
print "Your list is ",versions
sys.exit(255)
previous_line = line previous_line = line
if not 'micro_next' in version: if not 'micro_next' in version:
version['micro_next'] = version['micro']+1 version['micro_next'] = version['micro']+1
################################################################ version['string'] = '%(major)s.%(minor)s.%(micro)s' % (version)
version['filename'] = '%(name)s-%(string)s.tar.gz' % (version)
return version
archive_filename = '%(name)s-%(major)s.%(minor)s.%(micro)s.tar.gz' % (version) def check_file_does_not_exist(version):
if os.access(archive_filename, os.F_OK): if os.access(version['filename'], os.F_OK):
print "Sorry, you already have a file called %s! Please delete it or move it first." % (archive_filename) report_error("Sorry, you already have a file called %s! Please delete it or move it first." % (version['filename']))
sys.exit(255)
################################################################
changelog = file("ChangeLog").readlines()
# Find the most recent release.
def is_date(str): def is_date(str):
return len(str)>3 and str[4]=='-' return len(str)>3 and str[4]=='-'
def scan_changelog(version):
changelog = file("ChangeLog").readlines()
# Find the most recent release.
release_date = None release_date = None
for line in changelog: for line in changelog:
@ -145,12 +161,8 @@ for line in changelog:
if match: if match:
entries[-1] += ' (#%s)' % (match.group(1)) entries[-1] += ' (#%s)' % (match.group(1))
contributors_list = contributors.keys() # FIXME: getting complex enough we should be returning a dictionary
contributors_list.sort() return (contributors, changelog, entries, release_date)
thanksline = ', '.join([contributors[x] for x in contributors_list])
thanksline = thanksline.replace(contributors[contributors_list[-1]], 'and '+contributors[contributors_list[-1]])
version_string = '%(major)s.%(minor)s.%(micro)s' % (version)
def wordwrap(str, prefix=''): def wordwrap(str, prefix=''):
"Really simple wordwrap" "Really simple wordwrap"
@ -175,7 +187,27 @@ def wordwrap(str, prefix=''):
return '\n'.join(result).replace('(',' (') return '\n'.join(result).replace('(',' (')
thanks = '%s\n%s\n\n' % (version_string, '='*len(version_string)) def favourite_editor():
e = os.environ
if e.has_key('VISUAL'): return e['VISUAL']
if e.has_key('EDITOR'): return e['EDITOR']
if os.access('/usr/bin/nano', os.F_OK):
return '/usr/bin/nano'
report_error("I can't find an editor for you!")
def edit_news_entry(version):
# FIXME: still needs a lot of tidying up. Translator stuff especially needs to be
# factored out into a separate function.
(contributors, changelog, entries, release_date) = scan_changelog(version)
contributors_list = contributors.keys()
contributors_list.sort()
thanksline = ', '.join([contributors[x] for x in contributors_list])
thanksline = thanksline.replace(contributors[contributors_list[-1]], 'and '+contributors[contributors_list[-1]])
thanks = '%s\n%s\n\n' % (version['string'], '='*len(version['string']))
thanks += wordwrap('Thanks to %s for improvements in this version.' % (thanksline)) thanks += wordwrap('Thanks to %s for improvements in this version.' % (thanksline))
thanks += '\n\n' thanks += '\n\n'
for line in entries: for line in entries:
@ -213,7 +245,7 @@ thanks += '\n\n'
changes = '## '+ ' '.join(changelog).replace('\n', '\n## ') changes = '## '+ ' '.join(changelog).replace('\n', '\n## ')
filename = posixpath.expanduser("~/.release-wrangler-%(name)s-%(major)s-%(minor)s-%(micro)s.txt" % version) filename = posixpath.expanduser("~/.release-wrangler-%(name)s-%(string)s.txt" % version)
tmp = open(filename, 'w') tmp = open(filename, 'w')
tmp.write('## You are releasing %(name)s, version %(major)s.%(minor)s.%(micro)s.\n' % version) tmp.write('## You are releasing %(name)s, version %(major)s.%(minor)s.%(micro)s.\n' % version)
tmp.write('## The text at the foot of the page is the part of the ChangeLog which\n') tmp.write('## The text at the foot of the page is the part of the ChangeLog which\n')
@ -223,9 +255,7 @@ tmp.write(thanks)
tmp.write(changes) tmp.write(changes)
tmp.close() tmp.close()
os.spawnl(os.P_WAIT, '/bin/nano', 'nano', '+6', filename) os.system(favourite_editor()+' +6 %s ' % (filename))
################################################################
# Write it out to NEWS # Write it out to NEWS
@ -240,13 +270,14 @@ for line in open('NEWS').readlines():
news_tmp.close() news_tmp.close()
os.rename('NEWS.tmp', 'NEWS') os.rename('NEWS.tmp', 'NEWS')
changelog_and_checkin('NEWS', '%(major)s.%(minor)s.%(micro)s release.' % (version))
################################################################ def build_it_all(version):
"Now build the thing."
# Now build the thing.
autogen_prefix= '/prefix' # FIXME: this is specific to tthurman's laptop! autogen_prefix= '/prefix' # FIXME: this is specific to tthurman's laptop!
# FIXME: These should use os.system
if os.spawnl(os.P_WAIT, './autogen.sh', './autogen.sh', '--prefix', autogen_prefix) != 0: if os.spawnl(os.P_WAIT, './autogen.sh', './autogen.sh', '--prefix', autogen_prefix) != 0:
print 'autogen failed' print 'autogen failed'
sys.exit(255) sys.exit(255)
@ -263,15 +294,48 @@ if os.spawnl(os.P_WAIT, '/usr/bin/make', '/usr/bin/make', 'distcheck') != 0:
print 'distcheck failed' print 'distcheck failed'
sys.exit(255) sys.exit(255)
if not os.access(archive_filename, os.F_OK): if not os.access(version['filename'], os.F_OK):
print "Sorry, we don't appear to have a file called %s!" % (archive_filename) print "Sorry, we don't appear to have a file called %s!" % (archive_filename)
sys.exit(255) sys.exit(255)
# No, we won't have a configuration option to set your name on svn.g.o; that's def upload(version):
# No, we won't have a configuration option to set your name on master.g.o; that's
# what ~/.ssh/config is for. # what ~/.ssh/config is for.
print "Uploading..." print "Uploading..."
upload_result = commands.getstatusoutput('scp %s master.gnome.org:' % (archive_filename)) upload_result = commands.getstatusoutput('scp %s master.gnome.org:' % (version['filename']))
if upload_result[0]!=0: if upload_result[0]!=0:
print "There appears to have been an uploading problem: %d\n%s\n" % (upload_result[0], upload_result[1]) report_error("There appears to have been an uploading problem: %d\n%s\n" % (upload_result[0], upload_result[1]))
def increment_version(version):
configure_in = file('configure.in.tmp', 'w')
for line in file('configure.in'):
if re.search("^m4_define\(\[.*_micro_version\], \[(\d+)\]", line):
line = line.replace('[%(micro)s]' % version, '[%(micro_next)s]' % version)
configure_in.write(line)
configure_in.close()
os.rename('configure.in.tmp', 'configure.in')
changelog_and_checkin('configure.in', 'Post-release bump to %(major)s.%(minor)s.%(micro_next)s.' % version)
def tag_the_release(version):
version['ucname'] = name.upper()
os.system("svn cp -m release . svn+ssh://svn.gnome.org/svn/%(name)s/tags/%(ucname)s_%(major)s_%(minor)_%(micro)" % (version))
def main():
get_up_to_date()
check_we_are_up_to_date()
version = version_numbers()
check_file_does_not_exist(version)
edit_news_entry(version)
build_it_all(version)
tag_the_release(version)
increment_version(version)
upload(version)
print "-- Done --"
if __name__=='__main__':
main()