From 00251dfd77fc10bf1a9dc2ae20deccbf6517c29a Mon Sep 17 00:00:00 2001 From: Krista 'DarthMama' Bennett Date: Wed, 8 Jul 2020 15:39:05 +0200 Subject: [PATCH] Added (marginally tested) script to automate RC tagging and generation. python3 release_rc.py -h for options. --- release_rc.py | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 release_rc.py diff --git a/release_rc.py b/release_rc.py new file mode 100644 index 00000000..aeb27c2d --- /dev/null +++ b/release_rc.py @@ -0,0 +1,215 @@ +import subprocess +import re +import sys +import argparse + +parser = argparse.ArgumentParser(description='Automate the RC release process as sanely as possible.') +parser.add_argument('-r','--rev',nargs=1, help="revision number or changeset to tag as next RC") +group = parser.add_mutually_exclusive_group(required=False) +group.add_argument('-v','--version',nargs=4, type=int, help="force this version - bypasses version inference. Format: major minor patch RC") +group.add_argument('--rc', type=int, help="force this RC number on the inferred version") +args = parser.parse_args() + +# Note: we could get this from the macros, but since folks seem to be actually upgrading +# the release tag manually correctly and not the macro, let's just check both +cmd = ["hg", "log", "-r", ".", "--template", "\"{latesttag(r're:Release_[0-9]+\.[0-9]+\.[0-9]+-RC[0-9]+')}\""] +result = subprocess.run(cmd, capture_output=True) +release_string = result.stdout.decode("utf-8").replace('"','') +#print(release_string) + +changeset = args.rev # can be None :) + +major = -1 +minor = -1 +patch = -1 +rc = -1 + +if args.version: + major = args.version[0] + minor = args.version[1] + patch = args.version[2] + rc = args.version[3] + print(rc) + if (major < 0) or (minor < 0) or (patch < 0) or (rc < 0): + raise Exception("Version numbers must all be positive values.") +elif args.rc: + rc = args.rc + if (rc < 0): + raise Exception("RC numbers must all be positive values.") + +#define PEP_ENGINE_VERSION_MAJOR 2 +#define PEP_ENGINE_VERSION_MINOR 1 +#define PEP_ENGINE_VERSION_PATCH 0 +#define PEP_ENGINE_VERSION_RC 13 + +# Amateur hour. Biteme. +cmd = ["grep", "-E", "#define PEP_ENGINE_VERSION_[A-Z]+[ \t]+[0-9]+", "src/pEpEngine.h"] +result = subprocess.run(cmd, capture_output=True) +grep_output = result.stdout.decode("utf-8") +print(grep_output) + +if not args.version: + src_nums = [] + src_nums = re.findall(r'([0-9]+)', grep_output) + + if not src_nums: + raise Exception("Somehow, the source values for the engine versions were not found in src/pEpEngine.h. Aborting.") + if len(src_nums) != 4: + raise Exception("Somehow, we could not extract all version numbers from the header file src/pEpEngine.h. Aborting.") + + tag_nums = [] + if release_string.startswith("Release_"): + tag_nums = re.findall(r'([0-9]+)', release_string) + # for num in tagnums: + # print (num) + + if not tag_nums or len(tag_nums) != 4: + if not tag_nums: + print("Wow... there is no extant release tag. What did you do, wipe the repository?") + else: + print("Somehow, there was an error with the numbering of the tag \"" + release_string + "\"") + print("Do you want to continue? We'll make a tag from the source RC info. (Y/N)[enter]") + a = input().lower() + if not (a.startswith("y") or a.startswith("Y")): + sys.exit() + + force = False + + if len(tag_nums) == 4 and src_nums: + major_tag = int(tag_nums[0]) + major_src = int(src_nums[0]) + minor_tag = int(tag_nums[1]) + minor_src = int(src_nums[1]) + patch_tag = int(tag_nums[2]) + patch_src = int(src_nums[2]) + rc_tag = int(tag_nums[3]) + rc_src = int(src_nums[3]) + + print("Tagged: " + str(major_tag) + "." + str(minor_tag) + "." + str(patch_tag) + "." + str(rc_tag)) + print("Source: " + str(major_src) + "." + str(minor_src) + "." + str(patch_src) + "." + str(rc_src)) + + if (major_tag == major_src): + major = major_tag + if (minor_tag == minor_src): + minor = minor_tag + if (patch_tag == patch_src): + patch = patch_tag + # Hoorah, we're just changing the RC number. + if (rc < 0): + if (rc_tag == (rc_src - 1)): + # Best case! + rc = rc_src + elif (rc_tag == rc_src): + print("Someone was naughty and didn't bump the RC number in the src, or you made a mistake you want to fix.") + print("Current tagged version is " + str(major) + "." + str(minor) + "." + str(patch) + " RC" + rc_tag + ".") + print("(I)ncrement,(F)orce same version,(A)bort? [enter]") + a = input().lower() + a = lower(a) + if (a.startswith(i)): + rc = rc_tag + 1 + elif (a.startswith(f)): + rc = rc_tag + force = True + else: + print("Aborting...") + sys.exit() + else: + print("RC numbers are messed up. The last tagged version is " + str(rc_tag) + ", while the last source version is " + str(rc_src) + ".") + print("Please enter the RC version you want to use, followed by enter:") + a = input().lower() + rc = int(a) # Will raise value error if not a number. User deserves it, frankly. + + #Ok, we now have a value. Good. + + # This feels extremely suboptimal, but I'm tired and don't care + if (rc < 0): + if (major < 0): + if (major_src == major_tag + 1) and (minor_src == 0) and (patch_src == 0): + major = major_src + minor = 0 + patch = 0 + else: + print("Tagged release major version and source versions are too different for automatic deduction. Please do this manually.") + sys.exit() + elif (minor < 0): + if (minor_src == minor_tag + 1) and (patch_src == 0): + minor = minor_src + patch = 0 + else: + print("Tagged release major version and source versions are too different for automatic deduction. Please do this manually.") + sys.exit() + elif (patch_src == patch_tag + 1): + patch = patch_src + else: + print("Tagged release major version and source versions are too different for automatic deduction. Please do this manually.") + sys.exit() + # if we got this far, it was a version upgrade. + + if (rc_src > 0): + print("We detected a version upgrade, but the source indicates the next RC is RC " + str(rc_src)) + print("(K)eep,(R)eset to 0,(A)bort? [enter]") + a = input().lower() + + if a.startswith("k"): + rc = rc_src + elif a.startswith("r"): + rc = 0 + else: + print("Aborting...") + else: + rc = 0 + +# Ok, so now, after all that, we should have the right version numbers. + +# If there's no changeset to tag, we take the latest local default +if not changeset: + cmd = ["hg", "id", "-i", "-r", "default"] + result = subprocess.run(cmd, capture_output=True) + changeset = result.stdout.decode("utf-8").replace('"','').replace('\n','') + if not changeset: + raise Exception("Unable to determine latest default changeset. Aborting.") + + +rev_tag = "Release_" + str(major) + "." + str(minor) + "." + str(patch) + "-RC" + str(rc) + +print("Preparing to tag changeset " + changeset + " with tag " + rev_tag + ".\n\nProceed? (Y/N) [enter]") +a = input().lower() +if not (a.startswith("y")): + sys.exit() + +cmd = ["hg", "tag", "-r", changeset, rev_tag] +subprocess.run(cmd, check=True, capture_output=False) + +if not grep_output: + print("Information: Not writing version/RC info to src/pEpEngine.h") + sys.exit() + +# If successful, then bump the RC +with open('src/pEpEngine.h', 'r') as file : + filedata = file.read() + +grep_strs = grep_output.split("\n") + +cmd = ["grep", "-E", "#define PEP_ENGINE_VERSION[ \t]+\"[0-9]+.[0-9]+.[0-9]+\"", "src/pEpEngine.h"] +result = subprocess.run(cmd, capture_output=True) +grep_output = result.stdout.decode("utf-8") + +#define PEP_ENGINE_VERSION "2.1.0" +version_str = str(major) + "." + str(minor) + "." + str(patch) + +filedata = filedata.replace(grep_output, "#define PEP_ENGINE_VERSION \"" + version_str + "\"") +filedata = filedata.replace(grep_strs[0], "#define PEP_ENGINE_VERSION_MAJOR " + str(major)) +filedata = filedata.replace(grep_strs[1], "#define PEP_ENGINE_VERSION_MINOR " + str(minor)) +filedata = filedata.replace(grep_strs[2], "#define PEP_ENGINE_VERSION_PATCH " + str(patch)) +filedata = filedata.replace(grep_strs[3], "#define PEP_ENGINE_VERSION_RC " + str(rc + 1)) + +# Write the file out again +with open('src/pEpEngine.h', 'w') as file: + file.write(filedata) + +comment = "Automatically bumped next RC info to version " + version_str + "-RC" + str(rc + 1) +print("about to run with this comment:") +print(comment) +cmd = ["hg", "commit", "-m", comment] +subprocess.run(cmd, capture_output=False) +