3 # Copyright (C) 2009-2010 W. Trevor King <wking@drexel.edu>
5 # This file is part of Bugs Everywhere.
7 # Bugs Everywhere is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by the
9 # Free Software Foundation, either version 2 of the License, or (at your
10 # option) any later version.
12 # Bugs Everywhere is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Bugs Everywhere. If not, see <http://www.gnu.org/licenses/>.
26 from libbe.util.subproc import Pipe, invoke
27 from update_copyright import update_authors, update_files
30 INITIAL_COMMIT = '1bf1ec598b436f41ff27094eddf0b28c797e359d'
33 def validate_tag(tag):
35 >>> validate_tag('1.0.0')
36 >>> validate_tag('A.B.C-r7')
37 >>> validate_tag('A.B.C r7')
38 Traceback (most recent call last):
40 Exception: Invalid character ' ' in tag 'A.B.C r7'
42 Traceback (most recent call last):
44 Exception: Invalid character '"' in tag '"'
46 Traceback (most recent call last):
48 Exception: Invalid character ''' in tag '''
51 if char in string.digits:
53 elif char in string.letters:
55 elif char in ['.','-']:
57 raise Exception("Invalid character '%s' in tag '%s'" % (char, tag))
59 def pending_changes():
60 """Use `git diff`s output to detect change.
62 p = Pipe([['git', 'diff', 'HEAD']])
63 assert p.status == 0, p.statuses
64 if len(p.stdout) == 0:
68 def set_release_version(tag):
69 print "set libbe.version._VERSION = '%s'" % tag
70 p = Pipe([['sed', '-i', "s/^# *_VERSION *=.*/_VERSION = '%s'/" % tag,
71 os.path.join('libbe', 'version.py')]])
72 assert p.status == 0, p.statuses
74 def remove_makefile_libbe_version_dependencies():
75 print "set Makefile LIBBE_VERSION :="
76 p = Pipe([['sed', '-i', "s/^LIBBE_VERSION *:=.*/LIBBE_VERSION :=/",
78 assert p.status == 0, p.statuses
80 def commit(commit_message):
81 print 'commit current status:', commit_message
82 p = Pipe([['git', 'commit', '-m', commit_message]])
83 assert p.status == 0, p.statuses
86 print 'tag current revision', tag
87 p = Pipe([['git', 'tag', tag]])
88 assert p.status == 0, p.statuses
90 def export(target_dir):
91 print 'export current revision to', target_dir
92 p = Pipe([['git', 'archive', '--prefix', target_dir, 'HEAD'],
94 assert p.status == 0, p.statuses
97 print 'generate libbe/_version.py'
98 p = Pipe([['make', os.path.join('libbe', '_version.py')]])
99 assert p.status == 0, p.statuses
101 def make_changelog(filename, tag):
102 """Generate a ChangeLog from the git history.
104 Not the most ChangeLog-esque format, but iterating through commits
105 by hand is just too slow.
107 print 'generate ChangeLog file', filename, 'up to tag', tag
108 p = invoke(['git', 'log', '--no-merges',
109 '%s..%s' % (INITIAL_COMMIT, tag)],
110 stdout=open(filename, 'w')),
112 def set_vcs_name(filename, vcs_name='None'):
113 """Exported directory is not a git repository, so set vcs_name to
114 something that will work.
115 vcs_name: new_vcs_name
117 print 'set vcs_name in', filename, 'to', vcs_name
118 p = Pipe([['sed', '-i', "s/^vcs_name:.*/vcs_name: %s/" % vcs_name,
120 assert p.status == 0, p.statuses
122 def create_tarball(tag):
123 release_name='be-%s' % tag
124 export_dir = release_name
127 print 'copy libbe/_version.py to %s/libbe/_version.py' % export_dir
128 shutil.copy(os.path.join('libbe', '_version.py'),
129 os.path.join(export_dir, 'libbe', '_version.py'))
130 make_changelog(os.path.join(export_dir, 'ChangeLog'), tag)
131 set_vcs_name(os.path.join(export_dir, '.be', 'settings'))
132 tarball_file = '%s.tar.gz' % release_name
133 print 'create tarball', tarball_file
134 p = Pipe([['tar', '-czf', tarball_file, export_dir]])
135 assert p.status == 0, p.statuses
136 print 'remove', export_dir
137 shutil.rmtree(export_dir)
143 if __name__ == '__main__':
145 usage = """%prog [options] TAG
147 Create a git tag and a release tarball from the current revision.
151 You may wish to test this out in a dummy branch first to make sure it
152 works as expected to avoid the tedium of unwinding the version-bump
155 p = optparse.OptionParser(usage)
156 p.add_option('--test', dest='test', default=False,
157 action='store_true', help='Run internal tests and exit')
158 options,args = p.parse_args()
160 if options.test == True:
164 assert len(args) == 1, '%d (!= 1) arguments: %s' % (len(args), args)
168 if pending_changes() == True:
169 print "Handle pending changes before releasing."
171 set_release_version(tag)
174 commit("Bumped to version %s" % tag)