Skip to content

Commit 8905f66

Browse files
committed
added a check in piccolo CLI for migrations which haven't run
1 parent b7ba690 commit 8905f66

File tree

5 files changed

+103
-21
lines changed

5 files changed

+103
-21
lines changed

piccolo/apps/migrations/commands/check.py

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
1+
import dataclasses
2+
import typing as t
3+
14
from piccolo.apps.migrations.commands.base import BaseMigrationManager
25
from piccolo.apps.migrations.tables import Migration
36
from piccolo.utils.printing import get_fixed_length_string
47

58

9+
@dataclasses.dataclass
10+
class MigrationStatus:
11+
app_name: str
12+
migration_id: str
13+
has_ran: bool
14+
15+
616
class CheckMigrationManager(BaseMigrationManager):
717
def __init__(self, app_name: str):
818
self.app_name = app_name
919
super().__init__()
1020

11-
async def run(self):
12-
print("Listing migrations ...")
13-
21+
async def get_migration_statuses(self) -> t.List[MigrationStatus]:
1422
# Make sure the migration table exists, otherwise we'll get an error.
1523
await self.create_migration_table()
1624

17-
print(
18-
f'{get_fixed_length_string("APP NAME")} | '
19-
f'{get_fixed_length_string("MIGRATION_ID")} | RAN'
20-
)
25+
migration_statuses: t.List[MigrationStatus] = []
2126

2227
app_modules = self.get_app_modules()
2328

@@ -29,8 +34,6 @@ async def run(self):
2934
if (self.app_name != "all") and (self.app_name != app_name):
3035
continue
3136

32-
fixed_length_app_name = get_fixed_length_string(app_name)
33-
3437
migration_modules = self.get_migration_modules(
3538
app_config.migrations_folder_path
3639
)
@@ -44,11 +47,53 @@ async def run(self):
4447
)
4548
.run()
4649
)
47-
fixed_length_id = get_fixed_length_string(_id)
48-
print(
49-
f"{fixed_length_app_name} | {fixed_length_id} | {has_ran}"
50+
migration_statuses.append(
51+
MigrationStatus(
52+
app_name=app_name, migration_id=_id, has_ran=has_ran
53+
)
5054
)
5155

56+
return migration_statuses
57+
58+
async def have_ran_count(self) -> int:
59+
"""
60+
:returns:
61+
The number of migrations which have been ran.
62+
"""
63+
migration_statuses = await self.get_migration_statuses()
64+
return len([i for i in migration_statuses if i.has_ran])
65+
66+
async def havent_ran_count(self) -> int:
67+
"""
68+
:returns:
69+
The number of migrations which haven't been ran.
70+
"""
71+
migration_statuses = await self.get_migration_statuses()
72+
return len([i for i in migration_statuses if not i.has_ran])
73+
74+
async def run(self):
75+
"""
76+
Prints out the migrations which have and haven't ran.
77+
"""
78+
print("Listing migrations ...")
79+
80+
print(
81+
f'{get_fixed_length_string("APP NAME")} | '
82+
f'{get_fixed_length_string("MIGRATION_ID")} | RAN'
83+
)
84+
85+
migration_statuses = await self.get_migration_statuses()
86+
87+
for migration_status in migration_statuses:
88+
fixed_length_app_name = get_fixed_length_string(
89+
migration_status.app_name
90+
)
91+
fixed_length_id = get_fixed_length_string(
92+
migration_status.migration_id
93+
)
94+
has_ran = migration_status.has_ran
95+
print(f"{fixed_length_app_name} | {fixed_length_id} | {has_ran}")
96+
5297

5398
async def check(app_name: str = "all"):
5499
"""

piccolo/engine/postgres.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from piccolo.query.base import Query
1515
from piccolo.querystring import QueryString
1616
from piccolo.utils.sync import run_sync
17-
from piccolo.utils.warnings import colored_warning
17+
from piccolo.utils.warnings import colored_warning, colored_string, Level
1818

1919

2020
@dataclass
@@ -284,11 +284,14 @@ async def prep_database(self):
284284
)
285285
except InsufficientPrivilegeError:
286286
print(
287-
f"Unable to create {extension} extension - some "
288-
"functionality may not behave as expected. Make sure your "
289-
"database user has permission to create extensions, or "
290-
"add it manually using "
291-
f'`CREATE EXTENSION "{extension}";`'
287+
colored_string(
288+
f"=> Unable to create {extension} extension - some "
289+
"functionality may not behave as expected. Make sure "
290+
"your database user has permission to create "
291+
"extensions, or add it manually using "
292+
f'`CREATE EXTENSION "{extension}";`',
293+
level=Level.medium,
294+
)
292295
)
293296

294297
###########################################################################

piccolo/main.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,19 @@
33

44
from targ import CLI # type: ignore
55

6-
from piccolo.conf.apps import AppRegistry, Finder
76
from piccolo.apps.app.piccolo_app import APP_CONFIG as app_config
87
from piccolo.apps.asgi.piccolo_app import APP_CONFIG as asgi_config
98
from piccolo.apps.meta.piccolo_app import APP_CONFIG as meta_config
9+
from piccolo.apps.migrations.commands.check import CheckMigrationManager
1010
from piccolo.apps.migrations.piccolo_app import APP_CONFIG as migrations_config
1111
from piccolo.apps.playground.piccolo_app import APP_CONFIG as playground_config
1212
from piccolo.apps.project.piccolo_app import APP_CONFIG as project_config
1313
from piccolo.apps.shell.piccolo_app import APP_CONFIG as shell_config
1414
from piccolo.apps.sql_shell.piccolo_app import APP_CONFIG as sql_shell_config
1515
from piccolo.apps.user.piccolo_app import APP_CONFIG as user_config
16+
from piccolo.conf.apps import AppRegistry, Finder
17+
from piccolo.utils.sync import run_sync
18+
from piccolo.utils.warnings import colored_string, Level
1619

1720

1821
DIAGNOSE_FLAG = "--diagnose"
@@ -81,6 +84,33 @@ def main():
8184
continue
8285
cli.register(command, group_name=app_name)
8386

87+
# Show a warning if any migrations haven't been run.
88+
try:
89+
havent_ran_count = run_sync(
90+
CheckMigrationManager(app_name="all").havent_ran_count()
91+
)
92+
if havent_ran_count:
93+
message = (
94+
f"{havent_ran_count} migration hasn't"
95+
if havent_ran_count == 1
96+
else f"{havent_ran_count} migrations haven't"
97+
)
98+
print(
99+
colored_string(
100+
message=(
101+
"=> {} been run - the app "
102+
"might not behave as expected.\n"
103+
"To check which use:\n"
104+
" piccolo migrations check\n"
105+
"To run all migrations:\n"
106+
" piccolo migrations forwards all\n"
107+
).format(message),
108+
level=Level.high,
109+
)
110+
)
111+
except Exception:
112+
pass
113+
84114
###########################################################################
85115

86116
cli.run()

piccolo/utils/warnings.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ class Level(Enum):
1515
high = colorama.Fore.RED
1616

1717

18+
def colored_string(message: str, level: Level = Level.medium) -> str:
19+
return level.value + message + colorama.Fore.RESET
20+
21+
1822
def colored_warning(
1923
message: str,
2024
category: t.Type[Warning] = Warning,
@@ -36,5 +40,5 @@ def colored_warning(
3640
:level:
3741
Used to determine the colour of the text displayed to the user.
3842
"""
39-
colored_message = level.value + message + colorama.Fore.RESET
43+
colored_message = colored_string(message=message, level=level)
4044
warnings.warn(colored_message, category=category, stacklevel=stacklevel)

tests/apps/migrations/test_migration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55

66
class TestMigrationTable(TestCase):
77
def test_migration_table(self):
8-
Migration.create_table().run_sync()
8+
Migration.create_table(if_not_exists=True).run_sync()
99
Migration.select().run_sync()
1010
Migration.alter().drop_table().run_sync()

0 commit comments

Comments
 (0)