diff --git a/zcutil/make-release.py b/zcutil/make-release.py index 7d505c279..c19544312 100755 --- a/zcutil/make-release.py +++ b/zcutil/make-release.py @@ -26,6 +26,7 @@ def main(args=sys.argv[1:]): main_logged( opts.RELEASE_VERSION, opts.RELEASE_PREV, + opts.RELEASE_FROM, opts.RELEASE_HEIGHT, opts.HOTFIX, ) @@ -61,6 +62,11 @@ def parse_args(args): type=Version.parse_arg, help='The previously released version.', ) + p.add_argument( + 'RELEASE_FROM', + type=Version.parse_arg, + help='The previously released non-beta non-RC version. May be the same as RELEASE_PREV.', + ) p.add_argument( 'RELEASE_HEIGHT', type=int, @@ -70,8 +76,8 @@ def parse_args(args): # Top-level flow: -def main_logged(release, releaseprev, releaseheight, hotfix): - verify_releaseprev_tag(releaseprev) +def main_logged(release, releaseprev, releasefrom, releaseheight, hotfix): + verify_tags(releaseprev, releasefrom) verify_version(release, releaseprev, hotfix) initialize_git(release, hotfix) patch_version_in_files(release, releaseprev) @@ -82,7 +88,7 @@ def main_logged(release, releaseprev, releaseheight, hotfix): gen_manpages() commit('Updated manpages for {}.'.format(release.novtext)) - gen_release_notes(release) + gen_release_notes(release, releasefrom) update_debian_changelog(release) commit( 'Updated release notes and changelog for {}.'.format( @@ -101,8 +107,8 @@ def phase(message): return deco -@phase('Checking RELEASE_PREV tag.') -def verify_releaseprev_tag(releaseprev): +@phase('Checking tags.') +def verify_tags(releaseprev, releasefrom): candidates = [] # Any tag beginning with a 'v' followed by [1-9] must be a version @@ -130,6 +136,31 @@ def verify_releaseprev_tag(releaseprev): ), ) + candidates.reverse() + prev_tags = [] + for candidate in candidates: + if releasefrom == candidate: + break + else: + prev_tags.append(candidate) + else: + raise SystemExit( + '{} does not appear in `git tag --list`' + .format( + releasefrom.vtext, + ), + ) + + for tag in prev_tags: + if not tag.betarc: + raise SystemExit( + '{} appears to be a more recent non-beta non-RC release than {}' + .format( + tag.vtext, + releasefrom.vtext, + ), + ) + @phase('Checking version.') def verify_version(release, releaseprev, hotfix): @@ -238,8 +269,18 @@ def gen_manpages(): @phase('Generating release notes.') -def gen_release_notes(release): - sh_log('python', './zcutil/release-notes.py', '--version', release.novtext) +def gen_release_notes(release, releasefrom): + release_notes = [ + 'python', + './zcutil/release-notes.py', + '--version', + release.novtext, + '--prev', + releasefrom.vtext, + ] + if not release.betarc: + release_notes.append('--clear') + sh_log(*release_notes) sh_log( 'git', 'add', diff --git a/zcutil/release-notes.py b/zcutil/release-notes.py index 24adff0d0..b09c8774e 100755 --- a/zcutil/release-notes.py +++ b/zcutil/release-notes.py @@ -83,11 +83,14 @@ def document_authors(): f.write("{0} ({1})\n".format(n, c)) ## Writes release note to ./doc/release-notes based on git shortlog when current version number is specified -def generate_release_note(version, filename): +def generate_release_note(version, filename, prev, clear): print "Automatically generating release notes for {0} from git shortlog. Should review {1} for accuracy.".format(version, filename) - # fetches latest tags, so that latest_tag will be correct - subprocess.Popen(['git fetch -t'], shell=True, stdout=subprocess.PIPE).communicate()[0] - latest_tag = subprocess.Popen(['git describe --abbrev=0'], shell=True, stdout=subprocess.PIPE).communicate()[0].strip() + if prev: + latest_tag = prev + else: + # fetches latest tags, so that latest_tag will be correct + subprocess.Popen(['git fetch -t'], shell=True, stdout=subprocess.PIPE).communicate()[0] + latest_tag = subprocess.Popen(['git describe --abbrev=0'], shell=True, stdout=subprocess.PIPE).communicate()[0].strip() print "Previous release tag: ", latest_tag notes = subprocess.Popen(['git shortlog --no-merges {0}..HEAD'.format(latest_tag)], shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE).communicate()[0] lines = notes.split('\n') @@ -105,25 +108,32 @@ def generate_release_note(version, filename): f.writelines(notable_changes) f.writelines(RELEASE_NOTES_CHANGELOG_HEADING) f.writelines('\n'.join(lines)) - # Clear temporary release notes file - with open(temp_release_note, 'w') as f: - f.writelines(TEMP_RELEASE_NOTES_HEADER) + if clear: + # Clear temporary release notes file + with open(temp_release_note, 'w') as f: + f.writelines(TEMP_RELEASE_NOTES_HEADER) -def main(version, filename): +def main(version, filename, prev, clear): if version != None: - generate_release_note(version, filename) + generate_release_note(version, filename, prev, clear) document_authors() if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument('--version') + parser.add_argument('--version', help='Upcoming version, without leading v') + parser.add_argument('--prev', help='Previous version, with leading v') + parser.add_argument('--clear', help='Wipe doc/release-notes.md', action='store_true') args = parser.parse_args() root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) doc_dir = os.path.join(root_dir, 'doc') version = None filename = None + prev = None + clear = False if args.version: version = args.version filename = 'release-notes-{0}.md'.format(version) - main(version, filename) + prev = args.prev + clear = args.clear + main(version, filename, prev, clear)