#!/usr/bin/env python3 # src: # https://git.sr.ht/~sircmpwn/dotfiles/blob/f9e7e88a72c2b87e5ab823205cb3a3aa8f3babd0/bin/semver # usage: semver [patch|minor|major|] # desc: will tag a new version either based on last tag or # # patch(robertgzr) # allow tagging a new non-annotated release import os import subprocess import sys import tempfile import getopt simple_tag = True force = False changelog = True def usage(): print(f"usage: {sys.argv[0]} OPTIONS COMMANDS") print(""" bump the previous tag and create a new one OPTIONS: \t-h\tshow this help \t-a\tannotate tag \t-f\toverwrite existing tag \t-c\tdon't write changelog COMMANDS: \tpatch \tminor \tmajor """) sys.exit(2) try: opts, argv = getopt.getopt(sys.argv[1:], 'afch') except getopt.GetoptError as err: print(err) usage() for o, val in opts: if o == "-a": simple_tag = not simple_tag elif o == "-f": force = not force elif o == "-c": changelog = not changelog elif o == "-h": usage() else: assert False, "unhandled option" if any(item in ["-h", "--help", "help"] for item in argv): usage() if subprocess.run(["git", "branch", "--show-current"], stdout=subprocess.PIPE).stdout.decode().strip() != "master": print("WARNING! Not on the master branch.") subprocess.run(["git", "pull", "--rebase"]) p = subprocess.run(["git", "describe", "--abbrev=0", "--tags"], stdout=subprocess.PIPE) describe = p.stdout.decode().strip() # TODO also ask to re-append the trailing portion.... e.g. -rev1 prepend = '' if describe[0] == 'v': describe = describe[1:] prepend = 'v' old_version = describe.split("-")[0].split(".") if len(old_version) == 2: [major, minor] = old_version [major, minor] = map(int, [major, minor]) patch = 0 elif len(old_version) == 3: [major, minor, patch] = old_version [major, minor, patch] = map(int, [major, minor, patch]) else: print( f"WARNING: git describe returned invalid semver version: \"{describe}\"" ) sys.exit(1) # old_version = [0, 0, 0] p = subprocess.run( ["git", "shortlog", "--no-merges", f"{prepend}{describe}..HEAD"], stdout=subprocess.PIPE) shortlog = p.stdout.decode() new_version = None if argv[0] == "patch": patch += 1 elif argv[0] == "minor": minor += 1 patch = 0 elif argv[0] == "major": major += 1 minor = patch = 0 else: new_version = argv[0] if new_version is None: if len(old_version) == 2 and patch == 0: new_version = f"{major}.{minor}" else: new_version = f"{major}.{minor}.{patch}" if prepend is not '': new_version = prepend + new_version p = None if os.path.exists("contrib/_incr_version"): p = subprocess.run(["contrib/_incr_version", describe, new_version]) elif os.path.exists(".git/_incr_version"): print("Warning: _incr_version found at legacy path") p = subprocess.run([".git/_incr_version", describe, new_version]) else: print("Warning: no _incr_version script. " + "Does this project have any specific release requirements?") if p and p.returncode != 0: print("Error: _incr_version returned nonzero exit code") sys.exit(1) args = ["git", "tag"] if force: args.extend(["-f"]) if not simple_tag: with tempfile.NamedTemporaryFile() as f: basename = os.path.basename(os.getcwd()) f.write(f"{basename} {new_version}\n\n".encode()) f.write(shortlog.encode()) f.flush() args.extend(["-e", "-F", f.name, "-a", new_version]) subprocess.run(args) else: args.extend(["-m", new_version, new_version]) subprocess.run(args) if changelog: import time now = time.strftime("%Y-%m-%d", time.localtime()) with open("CHANGELOG", "r+") as f: data = f.read() f.seek(0) f.write(f"\n{new_version} ({now})\n\n") f.write(shortlog) f.write(data) f.flush()