Skip to content

Commit 33e4bc5

Browse files
Closes #262: Copy migrations table to branch (#263)
* Add migration to copy table to existing branches * Extend provision() method on Branch to copy migrations table * Logging tweak * Fix test
1 parent f012741 commit 33e4bc5

File tree

3 files changed

+76
-1
lines changed

3 files changed

+76
-1
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from django.db import connection, migrations
2+
3+
from netbox.plugins import get_plugin_config
4+
from netbox_branching.choices import BranchStatusChoices
5+
6+
7+
def copy_migrations(apps, schema_editor):
8+
"""
9+
Create a copy of the migrations table in each active branch.
10+
"""
11+
Branch = apps.get_model('netbox_branching', 'Branch')
12+
13+
table = 'django_migrations'
14+
schema_prefix = get_plugin_config('netbox_branching', 'schema_prefix')
15+
16+
with connection.cursor() as cursor:
17+
main_table = f'public.{table}'
18+
19+
for branch in Branch.objects.filter(status=BranchStatusChoices.READY):
20+
print(f'\n Copying migrations for branch {branch.name} ({branch.schema_id})...', end='')
21+
schema_name = f'{schema_prefix}{branch.schema_id}'
22+
schema_table = f'{schema_name}.{table}'
23+
24+
# Copy the migrations table to the branch schema
25+
cursor.execute(f"CREATE TABLE {schema_table} ( LIKE {main_table} INCLUDING INDEXES )")
26+
27+
# Copy table data
28+
cursor.execute(f"INSERT INTO {schema_table} SELECT * FROM {main_table}")
29+
30+
# Designate id as an identity column
31+
cursor.execute(f"ALTER TABLE {schema_table} ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY")
32+
33+
# Set the next value for the ID sequence
34+
cursor.execute("SELECT MAX(id) from django_migrations")
35+
starting_id = cursor.fetchone()[0] + 1
36+
cursor.execute(f"ALTER SEQUENCE {schema_name}.django_migrations_id_seq RESTART WITH {starting_id}")
37+
38+
print('\n ', end='') # Padding for final "OK"
39+
40+
41+
class Migration(migrations.Migration):
42+
43+
dependencies = [
44+
('netbox_branching', '0003_rename_indexes'),
45+
]
46+
47+
operations = [
48+
migrations.RunPython(
49+
code=copy_migrations,
50+
reverse_code=migrations.RunPython.noop
51+
),
52+
]

netbox_branching/models/branches.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,29 @@ def provision(self, user):
540540
f"ALTER TABLE {schema_table} ALTER COLUMN id SET DEFAULT nextval(%s)", [sequence_name]
541541
)
542542

543+
# Copy the migrations table
544+
main_table = f'{MAIN_SCHEMA}.django_migrations'
545+
schema_table = f'{schema}.django_migrations'
546+
logger.debug(f'Creating table {schema_table}')
547+
cursor.execute(
548+
f"CREATE TABLE {schema_table} ( LIKE {main_table} INCLUDING INDEXES )"
549+
)
550+
cursor.execute(
551+
f"INSERT INTO {schema_table} SELECT * FROM {main_table}"
552+
)
553+
# Designate id as an identity column
554+
cursor.execute(
555+
f"ALTER TABLE {schema_table} ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY"
556+
)
557+
# Set the next value for the ID sequence
558+
cursor.execute(
559+
f"SELECT MAX(id) from {schema_table}"
560+
)
561+
starting_id = cursor.fetchone()[0] + 1
562+
cursor.execute(
563+
f"ALTER SEQUENCE {schema}.django_migrations_id_seq RESTART WITH {starting_id}"
564+
)
565+
543566
# Replicate relevant tables from the main schema
544567
for table in get_tables_to_replicate():
545568
main_table = f'{MAIN_SCHEMA}.{table}'

netbox_branching/tests/test_branches.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def test_create_branch(self):
3838
"SELECT * FROM information_schema.tables WHERE table_schema=%s",
3939
[branch.schema_name]
4040
)
41-
tables_expected = {*tables_to_replicate, 'core_objectchange'}
41+
tables_expected = {*tables_to_replicate, 'core_objectchange', 'django_migrations'}
4242
tables_found = {row.table_name for row in fetchall(cursor)}
4343
self.assertSetEqual(tables_expected, tables_found)
4444

0 commit comments

Comments
 (0)