Files
Bot-Template/migrate.py
T
2026-05-29 09:51:18 +03:00

183 lines
7.5 KiB
Python

# - *- coding: utf- 8 - *-
import argparse
from typing import Optional
from alembic import command
from alembic.config import Config
HELP_TEXT = """
Миграции базы данных
Безопасное правило:
python migrate.py только показывает эту справку
действия с БД выполняются только при явной команде
Основные команды:
python migrate.py help показать эту справку
python migrate.py up применить все миграции до head
python migrate.py down откатить последнюю миграцию
python migrate.py new "add users" создать пустую миграцию
python migrate.py auto "add users" создать миграцию по SQLAlchemy-моделям
python migrate.py status показать текущую версию и последние версии
Длинные команды:
python migrate.py upgrade [rev] применить миграции до rev, по умолчанию head
python migrate.py downgrade [rev] откатить миграции до rev, по умолчанию -1
python migrate.py revision -m "name" создать пустую миграцию
python migrate.py current показать текущую версию БД
python migrate.py history показать историю миграций
python migrate.py heads показать последние версии веток
Короткие алиасы:
up -> upgrade
down -> downgrade
new -> revision
auto -> revision --autogenerate
autogen -> auto
cur -> current
hist -> history
st -> status
Подсказки:
- сначала меняешь SQLAlchemy-модель;
- потом запускаешь: python migrate.py auto "что изменилось";
- проверяешь файл в migrations/versions/;
- применяешь: python migrate.py up;
- если сомневаешься, запускаешь: python migrate.py status.
""".strip()
# Создаем parser без лишнего шума, чтобы help был похож на нормальную подсказку
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
description="Удобный CLI для Alembic-миграций",
formatter_class=argparse.RawTextHelpFormatter,
add_help=True,
)
subparsers = parser.add_subparsers(dest="command")
help_parser = subparsers.add_parser("help", aliases=["h"], help="Показать понятную справку")
help_parser.set_defaults(action=show_help)
upgrade_parser = subparsers.add_parser("upgrade", aliases=["up"], help="Применить миграции")
upgrade_parser.add_argument("revision", nargs="?", default="head", help="Версия миграции, по умолчанию head")
upgrade_parser.set_defaults(action=run_upgrade)
downgrade_parser = subparsers.add_parser("downgrade", aliases=["down"], help="Откатить миграции")
downgrade_parser.add_argument("revision", nargs="?", default="-1", help="Версия отката, по умолчанию -1")
downgrade_parser.set_defaults(action=run_downgrade)
revision_parser = subparsers.add_parser("revision", aliases=["new"], help="Создать пустую миграцию")
revision_parser.add_argument("message", nargs="?", help="Название миграции")
revision_parser.add_argument("-m", "--message-option", dest="message_option", help="Название миграции")
revision_parser.add_argument("--autogenerate", "-a", action="store_true", help="Собрать изменения из моделей")
revision_parser.set_defaults(action=run_revision)
auto_parser = subparsers.add_parser("auto", aliases=["autogen"], help="Создать миграцию по моделям")
auto_parser.add_argument("message", nargs="?", help="Название миграции")
auto_parser.add_argument("-m", "--message-option", dest="message_option", help="Название миграции")
auto_parser.set_defaults(action=run_auto_revision)
current_parser = subparsers.add_parser("current", aliases=["cur"], help="Показать текущую версию БД")
current_parser.set_defaults(action=run_current)
history_parser = subparsers.add_parser("history", aliases=["hist"], help="Показать историю миграций")
history_parser.set_defaults(action=run_history)
heads_parser = subparsers.add_parser("heads", help="Показать последние версии веток")
heads_parser.set_defaults(action=run_heads)
status_parser = subparsers.add_parser("status", aliases=["st"], help="Показать текущую версию и heads")
status_parser.set_defaults(action=run_status)
return parser
def show_help(_config: Optional[Config], _args: argparse.Namespace) -> None:
print(HELP_TEXT)
def run_upgrade(config: Config, args: argparse.Namespace) -> None:
print(f"Применяю миграции до версии: {args.revision}")
command.upgrade(config, args.revision)
print("Готово")
def run_downgrade(config: Config, args: argparse.Namespace) -> None:
print(f"Откатываю миграции до версии: {args.revision}")
command.downgrade(config, args.revision)
print("Готово")
def run_revision(config: Config, args: argparse.Namespace) -> None:
message = get_revision_message(args)
print(f"Создаю миграцию: {message}")
command.revision(config, message=message, autogenerate=args.autogenerate)
print("Готово")
def run_auto_revision(config: Config, args: argparse.Namespace) -> None:
message = get_revision_message(args)
print(f"Создаю миграцию по моделям: {message}")
command.revision(config, message=message, autogenerate=True)
print("Готово")
def run_current(config: Config, _args: argparse.Namespace) -> None:
print("Текущая версия БД:")
command.current(config)
def run_history(config: Config, _args: argparse.Namespace) -> None:
print("История миграций:")
command.history(config)
def run_heads(config: Config, _args: argparse.Namespace) -> None:
print("Последние версии миграций:")
command.heads(config)
def run_status(config: Config, args: argparse.Namespace) -> None:
run_current(config, args)
print()
run_heads(config, args)
def get_revision_message(args: argparse.Namespace) -> str:
message: Optional[str] = args.message_option or args.message
if not message:
raise SystemExit("Укажи название миграции. Пример: python migrate.py auto \"add users\"")
return message
def get_config() -> Config:
from tgbot.database.migration_runner import get_alembic_config
return get_alembic_config()
def main() -> None:
parser = build_parser()
args = parser.parse_args()
if args.command is None:
show_help(None, args)
return
if args.action == show_help:
show_help(None, args)
return
if args.action in (run_revision, run_auto_revision):
get_revision_message(args)
config = get_config()
args.action(config, args)
if __name__ == "__main__":
main()