Improve migration script with prompts, warnings, finish TODOs

This commit is contained in:
2024-10-23 18:34:24 -05:00
parent 9d116442a4
commit 110626048b
3 changed files with 94 additions and 14 deletions

View File

@@ -1,6 +1,9 @@
import os
import pkgutil
import re
import sys
from typing import Any, List, Optional
import questionary
from typing import Any, List, Optional, Tuple
from dotenv import load_dotenv
from peewee_migrate import Router, router
from peewee import PostgresqlDatabase
@@ -10,7 +13,7 @@ from linkpulse.formatting import pluralize
load_dotenv(dotenv_path=".env")
class ExtendedRouter(Router):
def show(self, module: str) -> Optional[str]:
def show(self, module: str) -> Optional[Tuple[str, str]]:
"""
Show the suggested migration that will be created, without actually creating it.
@@ -65,10 +68,6 @@ def main(*args: str) -> None:
router = ExtendedRouter(database=db, migrate_dir='linkpulse/migrations', ignore=[models.BaseModel._meta.table_name])
auto = 'linkpulse.models'
# TODO: Show unapplied migrations before applying all
# TODO: Suggest merging migrations if many are present + all applied
# TODO: Show prepared migration before naming (+ confirmation option for pre-provided name)
current = router.all_migrations()
if len(current) == 0:
diff = router.diff
@@ -82,15 +81,27 @@ def main(*args: str) -> None:
else:
print(f"Migration created: {migration}")
router.run(migration)
else:
print("{} migration{} found, applying all ({}).".format(len(diff), pluralize(len(diff)), ', '.join(diff)))
applied = router.run()
print('Done ({}).'.format(', '.join(applied)))
diff = router.diff
if len(diff) > 0:
print('Note: Selecting a migration will apply all migrations up to and including the selected migration.')
print('e.g. Applying 004 while only 001 is applied would apply 002, 003, and 004.')
choice = questionary.select("Select highest migration to apply:", choices=diff).ask()
if choice is None:
print("For safety reasons, you won't be able to create migrations without applying the pending ones.")
if len(current) == 0:
print("Warn: No migrations have been applied globally, which is dangerous. Something may be wrong.")
return
result = router.run(choice)
print(f"Done. Applied migrations: {result}")
print("Warning: You should commit and push any new migrations immediately!")
else:
print('No migrations found, all migrations applied.')
print("No pending migrations to apply.")
migration_available = router.show(auto)
if migration_available:
if migration_available is not None:
print("A migration is available to be applied:")
migrate_text, rollback_text = migration_available
@@ -104,7 +115,36 @@ def main(*args: str) -> None:
if line.strip() == '':
continue
print('\t' + line)
if questionary.confirm("Do you want to create this migration?").ask():
print('Lowercase letters and underscores only (e.g. "create_table", "remove_ipaddress_count").')
migration_name: Optional[str] = questionary.text("Enter migration name", validate=lambda text: re.match("^[a-z_]+$", text) is not None).ask()
if migration_name is None:
return
migration = router.create(migration_name, auto=auto)
if migration:
print(f"Migration created: {migration}")
if len(router.diff) == 1:
if questionary.confirm("Do you want to apply this migration immediately?").ask():
router.run(migration)
print('Done.')
print("!!! Commit and push this migration file immediately!")
else:
print("No changes detected. Something went wrong.")
return
else:
print("No database changes detected.")
if len(current) > 5:
if questionary.confirm("There are more than 5 migrations applied. Do you want to merge them?", default=False).ask():
print("Merging migrations...")
router.merge(name="initial")
print("Done.")
print("!!! Commit and push this merged migration file immediately!")
# Testing Code:
"""
print(router.print('linkpulse.models'))

41
backend/poetry.lock generated
View File

@@ -332,6 +332,20 @@ files = [
{file = "priority-2.0.0.tar.gz", hash = "sha256:c965d54f1b8d0d0b19479db3924c7c36cf672dbf2aec92d43fbdaf4492ba18c0"},
]
[[package]]
name = "prompt-toolkit"
version = "3.0.36"
description = "Library for building powerful interactive command lines in Python"
optional = false
python-versions = ">=3.6.2"
files = [
{file = "prompt_toolkit-3.0.36-py3-none-any.whl", hash = "sha256:aa64ad242a462c5ff0363a7b9cfe696c20d55d9fc60c11fd8e632d064804d305"},
{file = "prompt_toolkit-3.0.36.tar.gz", hash = "sha256:3e163f254bef5a03b146397d7c1963bd3e2812f0964bb9a24e6ec761fd28db63"},
]
[package.dependencies]
wcwidth = "*"
[[package]]
name = "psutil"
version = "6.0.0"
@@ -513,6 +527,20 @@ files = [
[package.extras]
cli = ["click (>=5.0)"]
[[package]]
name = "questionary"
version = "2.0.1"
description = "Python library to build pretty command line user prompts ⭐️"
optional = false
python-versions = ">=3.8"
files = [
{file = "questionary-2.0.1-py3-none-any.whl", hash = "sha256:8ab9a01d0b91b68444dff7f6652c1e754105533f083cbe27597c8110ecc230a2"},
{file = "questionary-2.0.1.tar.gz", hash = "sha256:bcce898bf3dbb446ff62830c86c5c6fb9a22a54146f0f5597d3da43b10d8fc8b"},
]
[package.dependencies]
prompt_toolkit = ">=2.0,<=3.0.36"
[[package]]
name = "six"
version = "1.16.0"
@@ -614,6 +642,17 @@ h11 = ">=0.8"
[package.extras]
standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"]
[[package]]
name = "wcwidth"
version = "0.2.13"
description = "Measures the displayed width of unicode strings in a terminal"
optional = false
python-versions = "*"
files = [
{file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"},
{file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"},
]
[[package]]
name = "wsproto"
version = "1.2.0"
@@ -631,4 +670,4 @@ h11 = ">=0.9.0,<1"
[metadata]
lock-version = "2.0"
python-versions = "^3.12"
content-hash = "297e93d8b8d987b9e98575c94874482c931fad147925d75f784fbc5138b1dad0"
content-hash = "5f79b30ae45d71568bbce44ede4d93ac6e0c0f580a818cf01e919745d23fa091"

View File

@@ -20,6 +20,7 @@ peewee-migrate = "^1.13.0"
types-peewee = "^3.17.7.20241017"
types-psycopg2 = "^2.9.21.20241019"
fastapi-cache2 = "^0.2.2"
questionary = "^2.0.1"
[tool.poetry.group.dev.dependencies]