Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto-execute all files from a glob or a dir #39

Merged
merged 5 commits into from
Oct 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions django_north/management/commands/migrate.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
import glob
import io
import logging
import os.path
Expand Down Expand Up @@ -77,21 +78,44 @@ def migrate(self):
def _load_schema_file(self, file_name, load_name=None):
file_path = os.path.join(
settings.NORTH_MIGRATIONS_ROOT, 'schemas', file_name)
self._load_schema_path(file_path, load_name or file_name)

def _load_schema_path(self, file_path, load_name):
if self.verbosity >= 1:
if load_name is None:
load_name = file_name
self.stdout.write(
self.style.MIGRATE_LABEL("Load {}".format(load_name)))
self.run_script(file_path)

def _load_schema_fullpath_file(self, file_path):
migration_root = os.path.join(
settings.NORTH_MIGRATIONS_ROOT, 'schemas')
load_name = os.path.relpath(file_path, migration_root)
self._load_schema_file(file_path, load_name)

def _load_schema_dir(self, dir_path):
for file_name in sorted(os.listdir(dir_path)):
file_path = os.path.join(dir_path, file_name)
if os.path.isfile(file_path) and file_path.endswith('.sql'):
self._load_schema_fullpath_file(file_path)

def _load_schema_string(self, input_string):
path = os.path.join(
settings.NORTH_MIGRATIONS_ROOT, 'schemas', input_string)

for file_path in sorted(glob.glob(path)):
if os.path.isdir(file_path):
self._load_schema_dir(file_path)
if os.path.isfile(file_path):
self._load_schema_fullpath_file(file_path)

def init_schema(self):
init_version = migrations.get_version_for_init()

# load first set of additional files
before_files = getattr(
settings, 'NORTH_BEFORE_SCHEMA_FILES', [])
for file_name in before_files:
self._load_schema_file(file_name)
self._load_schema_string(file_name)

# load additional files (deprecated)
additional_files = getattr(
Expand All @@ -115,7 +139,7 @@ def init_schema(self):
after_files = getattr(
settings, 'NORTH_AFTER_SCHEMA_FILES', [])
for file_name in after_files:
self._load_schema_file(file_name)
self._load_schema_string(file_name)

# load fixtures
try:
Expand Down
6 changes: 4 additions & 2 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ List of available settings:
* ``NORTH_ADDITIONAL_SCHEMA_FILES``: **deprecated** list of sql files to load before the schema.
For example: a file of DB roles, some extensions.
Default value: ``[]``
* ``NORTH_BEFORE_SCHEMA_FILES``: list of sql files to load before the schema.
* ``NORTH_BEFORE_SCHEMA_FILES``: list of sql files, dirs and globs to load before the schema.
If it's a dir or a glob, load only sql files in alphabetical order.
For example: a file of DB roles, some extensions.
Default value: ``[]``
* ``NORTH_AFTER_SCHEMA_FILES``: list of sql files to load after the schema.
* ``NORTH_AFTER_SCHEMA_FILES``: list of sql files, dirs and globs to load after the schema.
If it's a dir or a glob, load only sql files in alphabetical order.
For example: a file of permissions, grants on tables
Default value: ``[]``
* ``NORTH_CURRENT_VERSION_DETECTOR``: the current version detector.
Expand Down
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
152 changes: 152 additions & 0 deletions tests/test_migrate_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,158 @@ def test_migrate_init_full(capsys, settings, mocker):
)


def test_migrate_before_schema_glob(capsys, settings, mocker):
root = os.path.dirname(__file__)
settings.NORTH_MIGRATIONS_ROOT = os.path.join(root, 'test_data/sql')

mocker.patch(
'django_north.management.migrations.get_version_for_init',
return_value='16.12')
mock_run_script = mocker.patch(
'django_north.management.commands.migrate.Command.run_script')
command = migrate.Command()
command.verbosity = 2

# extensions, roles, fixtures, and grants
settings.NORTH_BEFORE_SCHEMA_FILES = ['glob_*.sql']
settings.NORTH_AFTER_SCHEMA_FILES = []
settings.NORTH_ADDITIONAL_SCHEMA_FILES = []
command.init_schema()
assert len(mock_run_script.call_args_list) == 5

base_path = os.path.join(settings.NORTH_MIGRATIONS_ROOT, 'schemas')
assert mock_run_script.call_args_list[0] == mocker.call(
os.path.join(base_path, 'glob_00.sql'))
assert mock_run_script.call_args_list[1] == mocker.call(
os.path.join(base_path, 'glob_01.sql'))
assert mock_run_script.call_args_list[2] == mocker.call(
os.path.join(base_path, 'glob_02.sql'))
captured = capsys.readouterr()
assert captured.out == (
'Load glob_00.sql\n'
'Load glob_01.sql\n'
'Load glob_02.sql\n'
'Load schema\n'
' Applying 16.12...\n'
'Load fixtures\n'
' Applying 16.12...\n'
)


def test_migrate_after_schema_glob(capsys, settings, mocker):
root = os.path.dirname(__file__)
settings.NORTH_MIGRATIONS_ROOT = os.path.join(root, 'test_data/sql')

mocker.patch(
'django_north.management.migrations.get_version_for_init',
return_value='16.12')
mock_run_script = mocker.patch(
'django_north.management.commands.migrate.Command.run_script')
command = migrate.Command()
command.verbosity = 2

# extensions, roles, fixtures, and grants
settings.NORTH_BEFORE_SCHEMA_FILES = []
settings.NORTH_AFTER_SCHEMA_FILES = ['glob_*.sql']
settings.NORTH_ADDITIONAL_SCHEMA_FILES = []
command.init_schema()
assert len(mock_run_script.call_args_list) == 5

base_path = os.path.join(settings.NORTH_MIGRATIONS_ROOT, 'schemas')
assert mock_run_script.call_args_list[1] == mocker.call(
os.path.join(base_path, 'glob_00.sql'))
assert mock_run_script.call_args_list[2] == mocker.call(
os.path.join(base_path, 'glob_01.sql'))
assert mock_run_script.call_args_list[3] == mocker.call(
os.path.join(base_path, 'glob_02.sql'))
captured = capsys.readouterr()
assert captured.out == (
'Load schema\n'
' Applying 16.12...\n'
'Load glob_00.sql\n'
'Load glob_01.sql\n'
'Load glob_02.sql\n'
'Load fixtures\n'
' Applying 16.12...\n'
)


def test_migrate_before_schema_dir(capsys, settings, mocker):
root = os.path.dirname(__file__)
settings.NORTH_MIGRATIONS_ROOT = os.path.join(root, 'test_data/sql')

mocker.patch(
'django_north.management.migrations.get_version_for_init',
return_value='16.12')
mock_run_script = mocker.patch(
'django_north.management.commands.migrate.Command.run_script')
command = migrate.Command()
command.verbosity = 2

# extensions, roles, fixtures, and grants
settings.NORTH_BEFORE_SCHEMA_FILES = ['dir']
settings.NORTH_AFTER_SCHEMA_FILES = []
settings.NORTH_ADDITIONAL_SCHEMA_FILES = []
command.init_schema()
assert len(mock_run_script.call_args_list) == 5

base_path = os.path.join(settings.NORTH_MIGRATIONS_ROOT, 'schemas', 'dir')
assert mock_run_script.call_args_list[0] == mocker.call(
os.path.join(base_path, 'file_00.sql'))
assert mock_run_script.call_args_list[1] == mocker.call(
os.path.join(base_path, 'file_01.sql'))
assert mock_run_script.call_args_list[2] == mocker.call(
os.path.join(base_path, 'file_02.sql'))
captured = capsys.readouterr()
assert captured.out == (
'Load dir/file_00.sql\n'
'Load dir/file_01.sql\n'
'Load dir/file_02.sql\n'
'Load schema\n'
' Applying 16.12...\n'
'Load fixtures\n'
' Applying 16.12...\n'
)


def test_migrate_after_schema_dir(capsys, settings, mocker):
root = os.path.dirname(__file__)
settings.NORTH_MIGRATIONS_ROOT = os.path.join(root, 'test_data/sql')

mocker.patch(
'django_north.management.migrations.get_version_for_init',
return_value='16.12')
mock_run_script = mocker.patch(
'django_north.management.commands.migrate.Command.run_script')
command = migrate.Command()
command.verbosity = 2

# extensions, roles, fixtures, and grants
settings.NORTH_BEFORE_SCHEMA_FILES = []
settings.NORTH_AFTER_SCHEMA_FILES = ['dir']
settings.NORTH_ADDITIONAL_SCHEMA_FILES = []
command.init_schema()
assert len(mock_run_script.call_args_list) == 5

base_path = os.path.join(settings.NORTH_MIGRATIONS_ROOT, 'schemas', 'dir')
assert mock_run_script.call_args_list[1] == mocker.call(
os.path.join(base_path, 'file_00.sql'))
assert mock_run_script.call_args_list[2] == mocker.call(
os.path.join(base_path, 'file_01.sql'))
assert mock_run_script.call_args_list[3] == mocker.call(
os.path.join(base_path, 'file_02.sql'))
captured = capsys.readouterr()
assert captured.out == (
'Load schema\n'
' Applying 16.12...\n'
'Load dir/file_00.sql\n'
'Load dir/file_01.sql\n'
'Load dir/file_02.sql\n'
'Load fixtures\n'
' Applying 16.12...\n'
)


def test_migrate_init_deprecation(capsys, settings, mocker):
root = os.path.dirname(__file__)
settings.NORTH_MIGRATIONS_ROOT = os.path.join(root, 'test_data/sql')
Expand Down