
* #39 Add Flask-Migrate dep * #39 Make it such that flask db init can run https://github.com/miguelgrinberg/Flask-Migrate/issues/196#issuecomment-381343393 * Run flask db init, update migrations.env, commit artifacts * Set up a script such that you can `docker-compose exec files bash -c 'cd /service; FLASK_APP="files/cli:app" flask '` and have it do whatever flask thing you want * Fix circular dependency * import * is evil * Initial alembic migration, has issues with constraints and nullable columns * Bring alts table up to date with alembic autogenerate * Rerun flask db revision autogenerate * Bring award_relationships table up to date with alembic autogenerate * [#39/alembic] files/classes/__init__.py is evil but is at least explicitly evil now * #39 fix model in files/classes/badges.py * #39 fix model in files/classes/domains.py and files/classes/clients.py * #39 fix models: comment saves, comment flags * #39 fix models: comments * Few more imports * #39 columns that are not nullable should be flagged as not nullable * #39 Add missing indexes to model defs * [#39] add missing unique constraints to model defs * [#39] Temporarily undo any model changes which cause the sqlalchemy model to be out of sync with the actual dump * #39 Deforeignkeyify the correct column to make alembic happy * #39 flask db revision --autogenerate now creates an empty migration * #39 Migration format such that files are listed in creation order * #39 Better first revision * #39 Revert the model changes that were required to get to zero differences between db revision --autogenerate and the existing schema * #39 The first real migration * #39 Ensure that foreign key constraints are named in migration * #39 Alembic migrations for FK constraints, column defs * [#39] Run DB migrations before starting tests * [#39] New test to ensure migrations are up to date * [#39] More descriptive test failure message * Add -T flag to docker-compose exec * [#39] Run alembic migrations when starting the container
78 lines
2.5 KiB
Python
78 lines
2.5 KiB
Python
import inspect
|
|
import migrations.versions
|
|
import os
|
|
import subprocess
|
|
|
|
from files.__main__ import app
|
|
|
|
APP_PATH = app.root_path
|
|
BASE_PATH = os.path.join(*os.path.split(APP_PATH)[:-1])
|
|
VERSIONS_PATH = migrations.versions.__path__._path[0];
|
|
|
|
def test_migrations_up_to_date():
|
|
def get_versions():
|
|
all_versions = [f.path for f in os.scandir(VERSIONS_PATH)]
|
|
filtered_versions = []
|
|
for entry in all_versions:
|
|
if not os.path.isfile(entry):
|
|
continue
|
|
*dir_parts, filename = os.path.split(entry)
|
|
base, ext = os.path.splitext(filename)
|
|
if ext == '.py':
|
|
filtered_versions.append(entry)
|
|
return filtered_versions
|
|
|
|
def get_method_body_lines(method):
|
|
method_lines, _ = inspect.getsourcelines(method)
|
|
return [l.strip() for l in method_lines if not l.strip().startswith('#')][1:]
|
|
|
|
versions_before = get_versions()
|
|
result = subprocess.run(
|
|
[
|
|
'python3',
|
|
'-m',
|
|
'flask',
|
|
'db',
|
|
'revision',
|
|
'--autogenerate',
|
|
'--rev-id=ci_verify_empty_revision',
|
|
'--message=should_be_empty',
|
|
],
|
|
cwd=BASE_PATH,
|
|
env={
|
|
**os.environ,
|
|
'FLASK_APP': 'files/cli:app',
|
|
},
|
|
capture_output=True,
|
|
text=True,
|
|
check=True
|
|
)
|
|
versions_after = get_versions()
|
|
new_versions = [v for v in versions_after if v not in versions_before]
|
|
try:
|
|
for version in new_versions:
|
|
filename = os.path.split(version)[-1]
|
|
base, ext = os.path.splitext(filename)
|
|
__import__(f'migrations.versions.{base}')
|
|
migration = getattr(migrations.versions, base)
|
|
upgrade_lines = get_method_body_lines(migration.upgrade)
|
|
assert ["pass"] == upgrade_lines, "\n".join([
|
|
"",
|
|
"Expected upgrade script to be empty (pass) but got",
|
|
*[f"\t>\t{l}" for l in upgrade_lines],
|
|
"To fix this issue, please run",
|
|
"\t$ flask db revision --autogenerate --message='short description of schema changes'",
|
|
"to generate a candidate migration, and make any necessary changes to that candidate migration (e.g. naming foreign key constraints)",
|
|
])
|
|
downgrade_lines = get_method_body_lines(migration.downgrade)
|
|
assert ["pass"] == downgrade_lines, "\n".join([
|
|
"",
|
|
"Expected downgrade script to be empty (pass) but got",
|
|
*[f"\t>{l}" for l in downgrade_lines],
|
|
"To fix this issue, please run",
|
|
"\tflask db revision --autogenerate --message='short description of schema changes'",
|
|
"to generate a candidate migration, and make any necessary changes to that candidate migration (e.g. naming foreign key constraints)",
|
|
])
|
|
finally:
|
|
for version in new_versions:
|
|
os.remove(version)
|