Skip to content

Commit

Permalink
Merge pull request #81 from peopledoc/old-migrations
Browse files Browse the repository at this point in the history
Disregard migrations older than the schema
  • Loading branch information
Joachim Jablon authored Jul 24, 2020
2 parents 8e8f5c8 + 60a6fe6 commit 100f23a
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 15 deletions.
17 changes: 15 additions & 2 deletions septentrion/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,9 @@ def get_fixtures_version(
return version


def build_migration_plan(settings: configuration.Settings) -> Iterable[Dict[str, Any]]:
def build_migration_plan(
settings: configuration.Settings, schema_version: versions.Version
) -> Iterable[Dict[str, Any]]:
"""
Return the list of migrations by version,
from the version used to init the DB to the current target version.
Expand All @@ -145,6 +147,9 @@ def build_migration_plan(settings: configuration.Settings) -> Iterable[Dict[str,
"version {} not found.".format(settings.TARGET_VERSION)
)

if schema_version:
versions_to_apply = list(utils.since(versions_to_apply, schema_version))

# get plan for each version to apply
for version in versions_to_apply:
version_plan = []
Expand Down Expand Up @@ -173,6 +178,14 @@ def build_migration_plan(settings: configuration.Settings) -> Iterable[Dict[str,
def describe_migration_plan(
settings: configuration.Settings, stylist: style.Stylist = style.noop_stylist
) -> None:

schema_version = get_best_schema_version(settings=settings)
with stylist.activate("title") as echo:
echo("Schema file version is {}".format(schema_version))

with stylist.activate("subtitle") as echo:
echo(" Migrations will start after {}".format(schema_version))

current_version = db.get_current_schema_version(settings=settings)
with stylist.activate("title") as echo:
echo("Current version is {}".format(current_version))
Expand All @@ -181,7 +194,7 @@ def describe_migration_plan(
with stylist.activate("title") as echo:
echo("Target version is {}".format(target_version))

for plan in build_migration_plan(settings=settings):
for plan in build_migration_plan(settings=settings, schema_version=schema_version):
version = plan["version"]
migrations = plan["plan"]

Expand Down
8 changes: 6 additions & 2 deletions septentrion/migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,21 @@ def migrate(
) -> None:

logger.info("Starting migrations")

schema_version = core.get_best_schema_version(settings=settings)

if not db.is_schema_initialized(settings=settings):
logger.info("Migration table is empty, loading a schema")
# schema not inited
schema_version = core.get_best_schema_version(settings=settings)
init_schema(settings=settings, init_version=schema_version, stylist=stylist)

# play migrations
with stylist.activate("title") as echo:
echo("Applying migrations")

for plan in core.build_migration_plan(settings=settings):
for plan in core.build_migration_plan(
settings=settings, schema_version=schema_version
):
version = plan["version"]
logger.info("Processing version %s", version)
with stylist.activate("subtitle") as echo:
Expand Down
13 changes: 13 additions & 0 deletions septentrion/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
All functions in here should be easily unit testable
"""

import itertools
from typing import Iterable, TypeVar

from septentrion import exceptions, versions
Expand Down Expand Up @@ -37,3 +38,15 @@ def until(iterable: Iterable[T], value: T) -> Iterable[T]:
break
else:
raise ValueError("{} not found".format(value))


def since(iterable: Iterable[T], value: T) -> Iterable[T]:
"""
Returns the values from iterable starting after the element is found
>>> list(until(range(300), 297))
[298, 299]
"""
it = itertools.dropwhile((lambda x: x != value), iterable)
# Drop the first element
next(it)
yield from it
47 changes: 36 additions & 11 deletions tests/unit/test_core.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import pathlib

import pytest

from septentrion import configuration, core, exceptions, versions
Expand All @@ -6,7 +8,7 @@

@pytest.fixture
def known_versions(mocker):
versions_ = [versions.Version.from_string(v) for v in ("1.1", "1.2", "1.3")]
versions_ = [versions.Version.from_string(v) for v in ("0", "1.1", "1.2", "1.3")]
mocker.patch("septentrion.core.files.get_known_versions", return_value=versions_)

return versions_
Expand Down Expand Up @@ -158,40 +160,45 @@ def test_build_migration_plan_unknown_version(known_versions):
settings = configuration.Settings(
target_version=versions.Version.from_string("1.5")
)
schema_version = versions.Version.from_string("0")

with pytest.raises(ValueError):
list(core.build_migration_plan(settings))
list(core.build_migration_plan(settings, schema_version=schema_version))


def test_build_migration_plan_ok(mocker, known_versions):
mocker.patch("septentrion.core.db.get_applied_migrations", return_value=[])
mocker.patch(
"septentrion.core.files.get_migrations_files_mapping",
return_value={
"file.ddl.sql": "tests/test_data/sql/17.1/manual/file.ddl.sql",
"file.dml.sql": "tests/test_data/sql/17.1/manual/file.dml.sql",
"file.ddl.sql": pathlib.Path(
"tests/test_data/sql/17.1/manual/file.ddl.sql"
),
"file.dml.sql": pathlib.Path(
"tests/test_data/sql/17.1/manual/file.dml.sql"
),
},
)
mocker.patch("septentrion.core.files.is_manual_migration", return_value=True)
settings = configuration.Settings(
target_version=versions.Version.from_string("1.2")
)

plan = core.build_migration_plan(settings=settings)
schema_version = versions.Version.from_string("0")
plan = core.build_migration_plan(settings=settings, schema_version=schema_version)

expected = [
{
"plan": [
(
"file.ddl.sql",
False,
"tests/test_data/sql/17.1/manual/file.ddl.sql",
pathlib.Path("tests/test_data/sql/17.1/manual/file.ddl.sql"),
True,
),
(
"file.dml.sql",
False,
"tests/test_data/sql/17.1/manual/file.dml.sql",
pathlib.Path("tests/test_data/sql/17.1/manual/file.dml.sql"),
True,
),
],
Expand All @@ -202,13 +209,13 @@ def test_build_migration_plan_ok(mocker, known_versions):
(
"file.ddl.sql",
False,
"tests/test_data/sql/17.1/manual/file.ddl.sql",
pathlib.Path("tests/test_data/sql/17.1/manual/file.ddl.sql"),
True,
),
(
"file.dml.sql",
False,
"tests/test_data/sql/17.1/manual/file.dml.sql",
pathlib.Path("tests/test_data/sql/17.1/manual/file.dml.sql"),
True,
),
],
Expand All @@ -227,10 +234,28 @@ def test_build_migration_plan_db_uptodate(mocker, known_versions):
target_version=versions.Version.from_string("1.2"),
)

plan = core.build_migration_plan(settings=settings)
schema_version = versions.Version.from_string("0")
plan = core.build_migration_plan(settings=settings, schema_version=schema_version)

expected = [
{"plan": [], "version": versions.Version.from_string("1.1")},
{"plan": [], "version": versions.Version.from_string("1.2")},
]
assert list(plan) == expected


def test_build_migration_plan_with_schema(mocker, known_versions):
mocker.patch(
"septentrion.core.db.get_applied_migrations", return_value=[],
)
settings = configuration.Settings(target_version="1.2")
schema_version = versions.Version.from_string("1.1")

plan = list(
core.build_migration_plan(settings=settings, schema_version=schema_version)
)

expected = [
{"plan": [], "version": versions.Version.from_string("1.2")},
]
assert list(plan) == expected

0 comments on commit 100f23a

Please sign in to comment.