diff --git a/Scripts/bump_build_number.py b/Scripts/bump_build_number.py index 6cff322e0..37fa26942 100755 --- a/Scripts/bump_build_number.py +++ b/Scripts/bump_build_number.py @@ -4,11 +4,29 @@ import os import re import commands import subprocess +import argparse +import inspect def fail(message): + file_name = __file__ + current_line_no = inspect.stack()[1][2] + current_function_name = inspect.stack()[1][3] + print 'Failure in:', file_name, current_line_no, current_function_name print message sys.exit(1) + +def execute_command(command): + try: + print ' '.join(command) + output = subprocess.check_output(command) + if output: + print output + except subprocess.CalledProcessError as e: + print e.output + sys.exit(1) + + def find_project_root(): path = os.path.abspath(os.curdir) @@ -25,8 +43,114 @@ def find_project_root(): path = new_path fail('Could not find project root path') + + +def is_valid_release_version(value): + regex = re.compile(r'^(\d+)\.(\d+)\.(\d+)$') + match = regex.search(value) + return match is not None + + +def is_valid_build_version(value): + # Internal builds have an option "i" suffix. + regex = re.compile(r'^(\d+)\.(\d+)\.(\d+)\.(\d+)i?$') + match = regex.search(value) + return match is not None + +def set_versions(plist_file_path, release_version, build_version): + if not is_valid_release_version(release_version): + fail('Invalid release version: %s' % release_version) + if not is_valid_build_version(build_version): + fail('Invalid build version: %s' % build_version) + + with open(plist_file_path, 'rt') as f: + text = f.read() + # print 'text', text + + # The "short" version is the release number. + # + # CFBundleShortVersionString + # 2.20.0 + # + # Internal builds have an option "i" suffix. + file_regex = re.compile(r'CFBundleShortVersionString\s*([\d\.]+)', re.MULTILINE) + file_match = file_regex.search(text) + # print 'match', match + if not file_match: + fail('Could not parse .plist') + text = text[:file_match.start(1)] + release_version + text[file_match.end(1):] + + # The "long" version is the build number. + # + # CFBundleVersion + # 2.20.0.3 + # + # Internal builds have an option "i" suffix. + file_regex = re.compile(r'CFBundleVersion\s*([\d\.]+i?)', re.MULTILINE) + file_match = file_regex.search(text) + # print 'match', match + if not file_match: + fail('Could not parse .plist') + text = text[:file_match.start(1)] + build_version + text[file_match.end(1):] + + with open(plist_file_path, 'wt') as f: + f.write(text) + + +def get_versions(plist_file_path): + with open(plist_file_path, 'rt') as f: + text = f.read() + # print 'text', text + + # CFBundleVersion + # 2.13.0.13 + # + # Internal builds have an option "i" suffix. + file_regex = re.compile(r'CFBundleVersion\s*([\d\.]+i?)', re.MULTILINE) + file_match = file_regex.search(text) + # print 'match', match + if not file_match: + fail('Could not parse .plist') + + # e.g. "2.13.0.13" + old_build_version = file_match.group(1) + print 'old_build_version:', old_build_version + + if not is_valid_build_version(old_build_version): + fail('Invalid build version: %s' % old_build_version) + + # Internal builds have an option "i" suffix. + build_number_regex = re.compile(r'\.(\d+)i?$') + build_number_match = build_number_regex.search(old_build_version) + if not build_number_match: + fail('Could not parse .plist version') + + # e.g. "13" + old_build_number = build_number_match.group(1) + print 'old_build_number:', old_build_number + + # Internal builds have an option "i" suffix. + release_number_regex = re.compile(r'^(.+)\.\d+i?$') + release_number_match = release_number_regex.search(old_build_version) + if not release_number_match: + fail('Could not parse .plist') + + # e.g. "2.13.0" + old_release_version = release_number_match.group(1) + print 'old_release_version:', old_release_version + + # Given "2.13.0.13", this should return "2.13.0" and "13" as strings. + return old_release_version, old_build_number + + if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Precommit cleanup script.') + parser.add_argument('--internal', action='store_true', help='flags internal builds by adding an "i" suffix to the build number.') + parser.add_argument('--version', help='used for starting a new version.') + + args = parser.parse_args() + project_root_path = find_project_root() # print 'project_root_path', project_root_path # plist_path @@ -54,75 +178,40 @@ if __name__ == '__main__': # --------------- # Main App # --------------- - with open(main_plist_path, 'rt') as f: - text = f.read() - # print 'text', text - # CFBundleVersion - # 2.13.0.13 - file_regex = re.compile(r'CFBundleVersion\s*([\d\.]+)', re.MULTILINE) - file_match = file_regex.search(text) - # print 'match', match - if not file_match: - fail('Could not parse .plist') + old_release_version, old_build_number = get_versions(main_plist_path) + + if args.version: + # e.g. --version 1.2.3 -> "1.2.3", "1.2.3.0" + new_release_version = args.version.strip() + new_build_version = new_release_version + ".0" + else: + new_build_number = str(1 + int(old_build_number)) + print 'new_build_number:', new_build_number - old_build_number = file_match.group(1) - print 'old_build_number:', old_build_number - - build_number_regex = re.compile(r'\.(\d+)$') - build_number_match = build_number_regex.search(old_build_number) - if not build_number_match: - fail('Could not parse .plist version') - - build_number = build_number_match.group(1) - build_number = str(1 + int(build_number)) - new_build_number = old_build_number[:build_number_match.start(1)] + build_number - print 'new_build_number:', new_build_number - - release_number_regex = re.compile(r'^(.+)\.\d+$') - release_number_match = release_number_regex.search(old_build_number) - if not release_number_match: - fail('Could not parse .plist version') - - release_number = release_number_match.group(1) - print 'release_number:', release_number - - text = text[:file_match.start(1)] + new_build_number + text[file_match.end(1):] - with open(main_plist_path, 'wt') as f: - f.write(text) + new_release_version = old_release_version + new_build_version = old_release_version + "." + new_build_number + + if args.internal: + new_build_version = new_build_version + "i" + + print 'new_release_version:', new_release_version + print 'new_build_version:', new_build_version + + set_versions(main_plist_path, new_release_version, new_build_version) # --------------- # Share Extension # --------------- - with open(share_ext_plist_path, 'rt') as f: - text = f.read() - # print 'text', text - # CFBundleVersion - # 2.13.0.13 - file_regex = re.compile(r'CFBundleShortVersionString\s*([\d\.]+)', re.MULTILINE) - file_match = file_regex.search(text) - # print 'match', match - if not file_match: - fail('Could not parse .plist') - text = text[:file_match.start(1)] + release_number + text[file_match.end(1):] - - # CFBundleVersion - # 2.13.0.13 - file_regex = re.compile(r'CFBundleVersion\s*([\d\.]+)', re.MULTILINE) - file_match = file_regex.search(text) - # print 'match', match - if not file_match: - fail('Could not parse .plist') - text = text[:file_match.start(1)] + new_build_number + text[file_match.end(1):] - - with open(share_ext_plist_path, 'wt') as f: - f.write(text) + set_versions(share_ext_plist_path, new_release_version, new_build_version) # --------------- # Git # --------------- - output = subprocess.check_output(['git', 'add', '.']) - output = subprocess.check_output(['git', 'commit', '-m', 'Bump build to %s.\n\n// FREEBIE' % new_build_number]) + command = ['git', 'add', '.'] + execute_command(command) + command = ['git', 'commit', '-m', '"Bump build to %s."' % new_build_version] + execute_command(command)