How do I check if Alembic migrations need to be generated?

Question:

I’m trying to improve CI pipeline to prevent situations where SQLAlchemy models are added or changed, but no Alembic migration is written or generated by the commit author from hitting the production branch.

alembic --help doesn’t seem to provide any helpful commands for this case, yet it already has all the metadata required (target_metadata variable) and the database credentials in env.py to make this happen.

What would be the best practice for implementing this check in CI?

Asked By: Nikolay Edigaryev

||

Answers:

Here’s a solution that I use. It’s a check that I have implemented as a test.

from alembic.autogenerate import compare_metadata
from alembic.command import upgrade
from alembic.runtime.migration import MigrationContext
from alembic.config import Config

from models.base import Base


def test_migrations_sane():
    """
    This test ensures that models defined by SQLAlchemy match what alembic migrations think
    the database should look like. If these are different, then once we have constructed
    the database via Alembic (via running all migrations) alembic will generate a set of changes to
    modify the database to match the schema defined by SQLAlchemy models. If these are the same,
    the set of changes is going to be empty. Which is exactly what we want to check.
    """
    engine = "SQLAlchemy DB Engine instance"
    try:
        with engine.connect() as connection:
            alembic_conf_file = "location of alembic.ini"
            alembic_config = Config(alembic_conf_file)
            upgrade(alembic_config, "head")
            mc = MigrationContext.configure(connection)
            diff = compare_metadata(mc, Base.metadata)

            assert diff == []
    finally:
        with engine.connect() as connection:
            # Resetting the DB
            connection.execute(
                """
                DROP SCHEMA public CASCADE;
                CREATE SCHEMA public;
                GRANT ALL ON SCHEMA public TO postgres;
                GRANT ALL ON SCHEMA public TO public;
                """
            )

EDIT: I noticed you linked a library that’s supposed to do the same thing. I gave it a go but it seems like it assumes that the database that it’s running the check against has to have had alembic run against it. My solution works against a blank db.

EDIT EDIT: Since leaving this answer, I have discovered the pytest-alembic package which offers this functionality and more. I have not used it personally but it seems pretty sweet.

Answered By: Vladimirs

There is alembic-autogen-check tool available: https://pypi.org/project/alembic-autogen-check/ Although it requires a database to be created to check upon.

Answered By: ziima