Skip to content

Commit c6db65e

Browse files
authored
let migrations have descriptions (piccolo-orm#166)
* let migrations have descriptions * added docs
1 parent 17832f8 commit c6db65e

File tree

8 files changed

+84
-16
lines changed

8 files changed

+84
-16
lines changed

docs/src/piccolo/migrations/create.rst

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ migration filename is a timestamp, which also serves as the migration ID.
1717
.. code-block:: bash
1818
1919
piccolo_migrations/
20-
2018-09-04T19:44:09.py
20+
2021-08-06T16-22-51-415781.py
2121
2222
The contents of an empty migration file looks like this:
2323

@@ -26,11 +26,13 @@ The contents of an empty migration file looks like this:
2626
from piccolo.apps.migrations.auto import MigrationManager
2727
2828
29-
ID = '2018-09-04T19:44:09'
29+
ID = '2021-08-06T16:22:51:415781'
30+
VERSION = "0.29.0" # The version of Piccolo used to create it
31+
DESCRIPTION = "Optional description"
3032
3133
3234
async def forwards():
33-
manager = MigrationManager(migration_id=ID)
35+
manager = MigrationManager(migration_id=ID, app_name="my_app", description=DESCRIPTION)
3436
3537
def run():
3638
print(f"running {ID}")
@@ -52,7 +54,9 @@ This is a **bad example**:
5254
5355
from ..tables import Band
5456
55-
ID = '2018-09-04T19:44:09'
57+
ID = '2021-08-06T16:22:51:415781'
58+
VERSION = "0.29.0" # The version of Piccolo used to create it
59+
DESCRIPTION = "Optional description"
5660
5761
5862
async def forwards():
@@ -69,6 +73,8 @@ someone runs your migrations in the future, they will get different results.
6973
Make your migrations completely independent of other code, so they're
7074
self contained and repeatable.
7175

76+
-------------------------------------------------------------------------------
77+
7278
Auto migrations
7379
---------------
7480

@@ -102,3 +108,19 @@ Auto migrations can accommodate most schema changes. There may be some rare edge
102108
cases where a single migration is trying to do too much in one go, and fails.
103109
To avoid these situations, create auto migrations frequently, and keep them
104110
fairly small.
111+
112+
-------------------------------------------------------------------------------
113+
114+
Migration descriptions
115+
----------------------
116+
117+
To make the migrations more memorable, you can give them a description. Inside
118+
the migration file, you can set a ``DESCRIPTION`` global variable manually, or
119+
can specify it when creating the migration:
120+
121+
.. code-block:: bash
122+
123+
piccolo migrations new my_app --auto --desc="Adding name column"
124+
125+
The Piccolo CLI will then use this description where appropriate when dealing
126+
with migrations.

piccolo/apps/migrations/auto/migration_manager.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ class MigrationManager:
126126

127127
migration_id: str = ""
128128
app_name: str = ""
129+
description: str = ""
129130
add_tables: t.List[DiffableTable] = field(default_factory=list)
130131
drop_tables: t.List[DiffableTable] = field(default_factory=list)
131132
rename_tables: t.List[RenameTable] = field(default_factory=list)

piccolo/apps/migrations/commands/check.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
class MigrationStatus:
1111
app_name: str
1212
migration_id: str
13+
description: str
1314
has_ran: bool
1415

1516

@@ -47,9 +48,15 @@ async def get_migration_statuses(self) -> t.List[MigrationStatus]:
4748
)
4849
.run()
4950
)
51+
description = getattr(
52+
migration_modules[_id], "DESCRIPTION", "-"
53+
)
5054
migration_statuses.append(
5155
MigrationStatus(
52-
app_name=app_name, migration_id=_id, has_ran=has_ran
56+
app_name=app_name,
57+
migration_id=_id,
58+
description=description,
59+
has_ran=has_ran,
5360
)
5461
)
5562

@@ -76,10 +83,13 @@ async def run(self):
7683
Prints out the migrations which have and haven't ran.
7784
"""
7885
print("Listing migrations ...")
86+
desc_length = 40
87+
id_length = 26
7988

8089
print(
8190
f'{get_fixed_length_string("APP NAME")} | '
82-
f'{get_fixed_length_string("MIGRATION_ID")} | RAN'
91+
f'{get_fixed_length_string("MIGRATION_ID", id_length)} | '
92+
f'{get_fixed_length_string("DESCRIPTION", desc_length)} | RAN'
8393
)
8494

8595
migration_statuses = await self.get_migration_statuses()
@@ -89,10 +99,18 @@ async def run(self):
8999
migration_status.app_name
90100
)
91101
fixed_length_id = get_fixed_length_string(
92-
migration_status.migration_id
102+
migration_status.migration_id, length=id_length
103+
)
104+
fixed_length_description = get_fixed_length_string(
105+
migration_status.description, desc_length
93106
)
94107
has_ran = migration_status.has_ran
95-
print(f"{fixed_length_app_name} | {fixed_length_id} | {has_ran}")
108+
print(
109+
f"{fixed_length_app_name} | "
110+
f"{fixed_length_id} | "
111+
f"{fixed_length_description} | "
112+
f"{has_ran}"
113+
)
96114

97115

98116
async def check(app_name: str = "all"):

piccolo/apps/migrations/commands/new.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class NoChanges(Exception):
8989

9090

9191
async def _create_new_migration(
92-
app_config: AppConfig, auto=False
92+
app_config: AppConfig, auto: bool = False, description: str = ""
9393
) -> NewMigrationMeta:
9494
"""
9595
Creates a new migration file on disk.
@@ -122,10 +122,11 @@ async def _create_new_migration(
122122
extra_imports=extra_imports,
123123
extra_definitions=extra_definitions,
124124
app_name=app_config.app_name,
125+
description=description,
125126
)
126127
else:
127128
file_contents = render_template(
128-
migration_id=meta.migration_id, auto=False
129+
migration_id=meta.migration_id, auto=False, description=description
129130
)
130131

131132
# Beautify the file contents a bit.
@@ -178,14 +179,17 @@ async def get_alter_statements(
178179
###############################################################################
179180

180181

181-
async def new(app_name: str, auto: bool = False):
182+
async def new(app_name: str, auto: bool = False, desc: str = ""):
182183
"""
183184
Creates a new migration file in the migrations folder.
184185
185186
:param app_name:
186187
The app to create a migration for.
187188
:param auto:
188189
Auto create the migration contents.
190+
:param desc:
191+
A description of what the migration does, for example 'adding name
192+
column'.
189193
190194
"""
191195
print("Creating new migration ...")
@@ -198,7 +202,9 @@ async def new(app_name: str, auto: bool = False):
198202

199203
_create_migrations_folder(app_config.migrations_folder_path)
200204
try:
201-
await _create_new_migration(app_config=app_config, auto=auto)
205+
await _create_new_migration(
206+
app_config=app_config, auto=auto, description=desc
207+
)
202208
except NoChanges:
203209
print("No changes detected - exiting.")
204210
sys.exit(0)

piccolo/apps/migrations/commands/templates/migration.py.jinja

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ from piccolo.apps.migrations.auto import MigrationManager
1111

1212
ID = '{{ migration_id }}'
1313
VERSION = '{{ version }}'
14+
DESCRIPTION = '{{ description }}'
1415

1516

1617
async def forwards():
17-
manager = MigrationManager(migration_id=ID, app_name="{{ app_name }}")
18+
manager = MigrationManager(migration_id=ID, app_name="{{ app_name }}", description=DESCRIPTION)
1819
{% if auto %}
1920
{% for alter_statement in alter_statements %}
2021
{{ alter_statement }}

piccolo/conf/apps.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

1717

1818
class MigrationModule(ModuleType):
19+
ID: str
20+
VERSION: str
21+
DESCRIPTION: str
22+
1923
@staticmethod
2024
async def forwards() -> None:
2125
pass

piccolo/utils/printing.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ def get_fixed_length_string(string: str, length=20) -> str:
22
"""
33
Add spacing to the end of the string so it's a fixed length.
44
"""
5-
spacing = "".join([" " for i in range(length - len(string))])
6-
fixed_length_string = f"{string}{spacing}"
5+
if len(string) > length:
6+
fixed_length_string = string[: length - 3] + "..."
7+
else:
8+
spacing = "".join([" " for i in range(length - len(string))])
9+
fixed_length_string = f"{string}{spacing}"
10+
711
return fixed_length_string

tests/utils/test_printing.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@
44

55

66
class TestGetFixedLengthString(TestCase):
7-
def test_get_fixed_length_string(self):
7+
def test_extra_padding(self):
8+
"""
9+
Make sure the additional padding is added.
10+
"""
811
result = get_fixed_length_string(string="hello", length=10)
912
self.assertEqual(result, "hello ")
13+
14+
def test_truncation(self):
15+
"""
16+
Make sure the string is truncated to the fixed length if it's too long.
17+
"""
18+
result = get_fixed_length_string(
19+
string="this is a very, very long string", length=20
20+
)
21+
self.assertEqual(result, "this is a very, v...")

0 commit comments

Comments
 (0)