69 lines
2.6 KiB
Python
Executable File
69 lines
2.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
import logging
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(
|
|
description="Create a tag at HEAD by bumping the highest local X.Y.Z or vX.Y.Z tag. "
|
|
"Preserves the latest tag's prefix; starts from v0.0.0 when no version tags exist.",
|
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
)
|
|
group = parser.add_mutually_exclusive_group(required=True)
|
|
for part in ("major", "minor", "patch"):
|
|
group.add_argument(f"--{part}", dest="part", action="store_const", const=part,
|
|
help=f"Bump the {part} version and reset lower components")
|
|
parser.add_argument("--cwd", type=Path, default=Path.cwd(), help="Git repository directory")
|
|
parser.add_argument("--push", action="store_true", help="Push only the new tag to origin")
|
|
return parser.parse_args()
|
|
|
|
|
|
def git(cwd: Path, arguments: list[str]) -> str:
|
|
result = subprocess.run(
|
|
args=["git", *arguments], cwd=cwd, check=True, capture_output=True, text=True,
|
|
)
|
|
return result.stdout.strip()
|
|
|
|
|
|
def next_tag(tags: list[str], part: str) -> str:
|
|
versions = []
|
|
for tag in tags:
|
|
match = re.fullmatch(r"(v?)(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)", tag)
|
|
if match:
|
|
versions.append((tuple(int(value) for value in match.groups()[1:]), match[1]))
|
|
version, prefix = max(versions, default=((0, 0, 0), "v"))
|
|
components = list(version)
|
|
index = ("major", "minor", "patch").index(part)
|
|
components[index] += 1
|
|
components[index + 1:] = [0] * (2 - index)
|
|
return f"{prefix}{'.'.join(str(value) for value in components)}"
|
|
|
|
|
|
def main() -> int:
|
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s: %(message)s")
|
|
arguments = parse_args()
|
|
try:
|
|
tags = git(cwd=arguments.cwd, arguments=["tag", "--list"]).splitlines()
|
|
tag = next_tag(tags=tags, part=arguments.part)
|
|
git(cwd=arguments.cwd, arguments=["tag", "--", tag, "HEAD"])
|
|
logging.info(f"Created {tag} at HEAD")
|
|
if arguments.push:
|
|
git(cwd=arguments.cwd, arguments=["push", "origin", f"refs/tags/{tag}:refs/tags/{tag}"])
|
|
logging.info(f"Pushed {tag} to origin")
|
|
except subprocess.CalledProcessError as error:
|
|
logging.error(f"Git failed: {(error.stderr or str(error)).strip()}")
|
|
return 1
|
|
except OSError as error:
|
|
logging.error(f"{error}")
|
|
return 1
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|