1
1
mirror of https://github.com/yandex/pgmigrate.git synced 2024-11-08 22:11:31 +03:00

Raise error on missing migrations directory

This change is based on proposal by Ernst Haagsman
This commit is contained in:
secwall 2017-12-02 21:44:49 +03:00
parent 671dc3c0c7
commit 76c828baf9
4 changed files with 56 additions and 40 deletions

View File

@ -4,6 +4,7 @@ People that contributed to it:
Alexander Artemenko <art@yandex-team.ru>
Alexander Klyuev <wizard@yandex-team.ru>
Ernst Haagsman <ernst.haagsman@jetbrains.com>
Evgeny Dyukov <secwall@yandex-team.ru>
Vadim Bahmatovich <bahmatovich.v@gmail.com>
Vladimir Antipin <avmhawk@gmail.com>

View File

@ -27,6 +27,12 @@ Feature: Handling migration errors
And database has no schema_version table
And migrate command failed with Unknown target
Scenario: Missing migrations subdir
Given migration dir
And removed migrations subdir
When we run pgmigrate with "-t 1 migrate"
Then migrate command failed with Migrations dir not found
Scenario: Wrong schema_version structure
Given migration dir
And database and connection

View File

@ -6,7 +6,7 @@ from behave import given
@given('migration dir')
def step_impl(context):
def step_migrations_dir(context):
try:
shutil.rmtree(context.migr_dir)
except Exception:
@ -14,3 +14,8 @@ def step_impl(context):
context.migr_dir = tempfile.mkdtemp()
os.mkdir(os.path.join(context.migr_dir, 'migrations'))
os.mkdir(os.path.join(context.migr_dir, 'callbacks'))
@given('removed migrations subdir')
def step_removed_subdir(context):
shutil.rmtree(os.path.join(context.migr_dir, 'migrations'))

View File

@ -71,7 +71,7 @@ class MalformedSchema(MigrateError):
pass
class ConfigParseError(MigrateError):
class ConfigurationError(MigrateError):
"""
Incorrect config or cmd args exception
"""
@ -139,7 +139,7 @@ MIGRATION_FILE_RE = re.compile(
)
MigrationInfo = namedtuple('MigrationInfo', ('meta', 'filePath'))
MigrationInfo = namedtuple('MigrationInfo', ('meta', 'file_path'))
Callbacks = namedtuple('Callbacks', ('beforeAll', 'beforeEach',
'afterEach', 'afterAll'))
@ -157,36 +157,39 @@ def _get_migrations_info_from_dir(base_dir):
"""
path = os.path.join(base_dir, 'migrations')
migrations = {}
if os.path.exists(path) and os.path.isdir(path):
for fname in os.listdir(path):
file_path = os.path.join(path, fname)
if not os.path.isfile(file_path):
continue
match = MIGRATION_FILE_RE.match(fname)
if match is None:
continue
version = int(match.group('version'))
ret = dict(
version=version,
type='auto',
installed_by=None,
installed_on=None,
description=match.group('description').replace('_', ' '),
)
ret['transactional'] = 'NONTRANSACTIONAL' not in ret['description']
migration = MigrationInfo(
ret,
file_path,
)
if version in migrations:
raise MalformedMigration((
'Found migrations with same version: {version} '
'\nfirst : {first_path}'
'\nsecond: {second_path}').format(
version=version,
first_path=migration.filePath,
second_path=migrations[version].filePath))
migrations[version] = migration
if not (os.path.exists(path) and os.path.isdir(path)):
raise ConfigurationError(
'Migrations dir not found (expected to be {path})'.format(
path=path))
for fname in os.listdir(path):
file_path = os.path.join(path, fname)
if not os.path.isfile(file_path):
continue
match = MIGRATION_FILE_RE.match(fname)
if match is None:
continue
version = int(match.group('version'))
ret = dict(
version=version,
type='auto',
installed_by=None,
installed_on=None,
description=match.group('description').replace('_', ' '),
)
ret['transactional'] = 'NONTRANSACTIONAL' not in ret['description']
migration = MigrationInfo(
ret,
file_path,
)
if version in migrations:
raise MalformedMigration((
'Found migrations with same version: {version} '
'\nfirst : {first_path}'
'\nsecond: {second_path}').format(
version=version,
first_path=migration.file_path,
second_path=migrations[version].file_path))
migrations[version] = migration
return migrations
@ -355,7 +358,7 @@ def _apply_version(version, base_dir, user, cursor):
version_info = all_versions[version]
LOG.info('Try apply version %r', version_info)
_apply_file(version_info.filePath, cursor)
_apply_file(version_info.file_path, cursor)
cursor.execute('INSERT INTO public.schema_version '
'(version, description, installed_by) '
'VALUES (%s::bigint, %s, %s)',
@ -371,11 +374,12 @@ def _parse_str_callbacks(callbacks, ret, base_dir):
continue
tokens = callback.split(':')
if tokens[0] not in ret._fields:
raise ConfigParseError('Unexpected callback '
'type: {type}'.format(type=text(tokens[0])))
raise ConfigurationError(
'Unexpected callback '
'type: {type}'.format(type=text(tokens[0])))
path = os.path.join(base_dir, tokens[1])
if not os.path.exists(path):
raise ConfigParseError(
raise ConfigurationError(
'Path unavailable: {path}'.format(path=text(path)))
if os.path.isdir(path):
for fname in sorted(os.listdir(path)):
@ -392,7 +396,7 @@ def _parse_dict_callbacks(callbacks, ret, base_dir):
for j in callbacks[i]:
path = os.path.join(base_dir, j)
if not os.path.exists(path):
raise ConfigParseError(
raise ConfigurationError(
'Path unavailable: {path}'.format(path=text(path)))
if os.path.isdir(path):
for fname in sorted(os.listdir(path)):
@ -400,7 +404,7 @@ def _parse_dict_callbacks(callbacks, ret, base_dir):
else:
getattr(ret, i).append(path)
else:
raise ConfigParseError(
raise ConfigurationError(
'Unexpected callback type: {type}'.format(type=text(i)))
return ret
@ -657,7 +661,7 @@ def get_config(base_dir, args=None):
if conf.user is None:
conf = conf._replace(user=_get_database_user(conf.cursor))
elif not conf.user:
raise ConfigParseError('Empty user name')
raise ConfigurationError('Empty user name')
return conf