2024-10-02 10:23:23 +02:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
|
|
from dataclasses import dataclass
|
|
|
|
from pathlib import Path
|
|
|
|
from typing import Any
|
|
|
|
|
|
|
|
from shared.changelog import update_changelog_to_new_version
|
|
|
|
from shared.git import Git
|
|
|
|
from shared.paths import PROJECT_PATHS
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class Options:
|
|
|
|
stable_branch: str = "stable"
|
|
|
|
develop_branch: str = "develop"
|
|
|
|
|
|
|
|
|
|
|
|
class BaseCommand:
|
|
|
|
name: str = NotImplemented
|
|
|
|
help: str = NotImplemented
|
|
|
|
|
|
|
|
def __init__(self, git: Git) -> None:
|
|
|
|
self.git = git
|
|
|
|
|
|
|
|
def decorate_parser(self, parser: argparse.ArgumentParser) -> None:
|
|
|
|
parser.add_argument("game_version", choices=[1, 2], type=int)
|
|
|
|
parser.add_argument("version")
|
|
|
|
|
|
|
|
def run(self, args: argparse.Namespace, options: Options) -> None:
|
|
|
|
raise NotImplementedError("not implemented")
|
|
|
|
|
|
|
|
|
|
|
|
class CommitCommand(BaseCommand):
|
|
|
|
name = "commit"
|
|
|
|
help = "Create and tag a commit with the release information"
|
|
|
|
|
|
|
|
def decorate_parser(self, parser: argparse.ArgumentParser) -> None:
|
|
|
|
super().decorate_parser(parser)
|
|
|
|
parser.add_argument(
|
|
|
|
"-d",
|
|
|
|
"--dry-run",
|
|
|
|
action="store_true",
|
|
|
|
help="only output the changelog to stdout, do not commit anything",
|
|
|
|
)
|
|
|
|
|
|
|
|
def run(self, args: argparse.Namespace, options: Options) -> None:
|
|
|
|
# self.git.checkout_branch("develop")
|
2025-02-16 23:32:07 +01:00
|
|
|
old_tag = self.git.get_branch_version(
|
|
|
|
pattern=f"tr{args.game_version}-*",
|
|
|
|
branch="origin/stable",
|
|
|
|
abbrev=0,
|
|
|
|
)
|
2024-10-02 10:23:23 +02:00
|
|
|
new_tag = f"tr{args.game_version}-{args.version}"
|
|
|
|
|
|
|
|
changelog_path = PROJECT_PATHS[args.game_version].changelog_path
|
|
|
|
old_changelog = changelog_path.read_text()
|
|
|
|
new_changelog = update_changelog_to_new_version(
|
|
|
|
old_changelog,
|
|
|
|
old_tag=old_tag,
|
|
|
|
new_tag=new_tag,
|
|
|
|
new_version_name=args.version,
|
|
|
|
stable_branch=options.stable_branch,
|
|
|
|
develop_branch=options.develop_branch,
|
|
|
|
)
|
|
|
|
if old_changelog == new_changelog:
|
|
|
|
return
|
|
|
|
|
|
|
|
if args.dry_run:
|
|
|
|
print(new_changelog, end="")
|
|
|
|
return
|
|
|
|
|
|
|
|
changelog_path.write_text(new_changelog)
|
|
|
|
self.git.add(changelog_path)
|
|
|
|
self.git.commit(f"docs/tr{args.game_version}: release {args.version}")
|
|
|
|
|
|
|
|
|
|
|
|
class BranchCommand(BaseCommand):
|
|
|
|
name = "branch"
|
|
|
|
help = "Merge branch to the specified tag"
|
|
|
|
|
|
|
|
def run(self, args: argparse.Namespace, options: Options) -> None:
|
|
|
|
new_tag = f"tr{args.game_version}-{args.version}"
|
|
|
|
self.git.checkout_branch("stable")
|
2025-02-16 23:32:07 +01:00
|
|
|
self.git.merge_reset(
|
2025-03-18 22:39:16 +01:00
|
|
|
"develop", text=f"tr{args.game_version}: release {args.version}"
|
2025-02-16 23:32:07 +01:00
|
|
|
)
|
|
|
|
self.git.delete_tag(new_tag)
|
|
|
|
self.git.create_tag(new_tag)
|
2024-10-02 10:23:23 +02:00
|
|
|
self.git.checkout_branch("develop")
|
|
|
|
|
|
|
|
|
|
|
|
class PushCommand(BaseCommand):
|
|
|
|
name = "push"
|
|
|
|
help = (
|
|
|
|
"Push the develop and stable branches, and the version tag to GitHub"
|
|
|
|
)
|
|
|
|
|
|
|
|
def decorate_parser(self, parser: argparse.ArgumentParser) -> None:
|
|
|
|
super().decorate_parser(parser)
|
|
|
|
parser.add_argument(
|
|
|
|
"-f",
|
|
|
|
"--force",
|
|
|
|
action="store_true",
|
|
|
|
help="force push all targets",
|
|
|
|
)
|
|
|
|
|
|
|
|
def run(self, args: argparse.Namespace, options: Options) -> None:
|
|
|
|
new_tag = f"tr{args.game_version}-{args.version}"
|
|
|
|
self.git.push(
|
|
|
|
"origin",
|
|
|
|
["develop", "stable", new_tag],
|
|
|
|
force=args.force,
|
|
|
|
force_with_lease=not args.force,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def parse_args(commands: list[BaseCommand]) -> None:
|
|
|
|
parser = argparse.ArgumentParser(
|
|
|
|
description="Argument parser with subcommands"
|
|
|
|
)
|
|
|
|
subparsers = parser.add_subparsers(title="subcommands", dest="subcommand")
|
|
|
|
for command in commands:
|
|
|
|
subparser = subparsers.add_parser(command.name, help=command.help)
|
|
|
|
command.decorate_parser(subparser)
|
|
|
|
subparser.set_defaults(command=command)
|
|
|
|
|
|
|
|
result = parser.parse_args()
|
|
|
|
if not hasattr(result, "command"):
|
|
|
|
parser.error("missing command")
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
def main() -> None:
|
|
|
|
git = Git()
|
|
|
|
commands = [
|
|
|
|
command_cls(git=git) for command_cls in BaseCommand.__subclasses__()
|
|
|
|
]
|
|
|
|
options = Options()
|
|
|
|
args = parse_args(commands)
|
|
|
|
args.command.run(args, options)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|