From 7b16abbae1d3af0e57730be872cef6b1f7d7a244 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 14 May 2019 08:42:25 +0000 Subject: [PATCH] [IMP] core: add support for multi-version migration scripts A special folder named `0.0.0` can contain scripts that are run on upgrade of any version. They are useful to make some sanity checks or other verifications to ensure database consistency. The first version of this patch used the more eye-catching `any` for the migration folder, but it was problematic for upgrading from an older version that doesn't contain this patch. Using a version "number" containing two dots is required to avoid it being prefixed with the server version (see `convert_version` method) and resulting in a version like `10.0.any`. Such version would have been executed, even without this patch, when upgrading from an older major server version (9.0.1.0 < 10.0.any). closes odoo/odoo#34268 Signed-off-by: Christophe Simonis --- odoo/modules/migration.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/odoo/modules/migration.py b/odoo/modules/migration.py index 78025cbfa11..2bff1201bac 100644 --- a/odoo/modules/migration.py +++ b/odoo/modules/migration.py @@ -28,6 +28,8 @@ class MigrationManager(object): Python file names must start by `pre-` or `post-` and will be executed, respectively, before and after the module initialisation. `end-` scripts are run after all modules have been updated. + A special folder named `0.0.0` can contain scripts that will be run on any version change. + In `pre` stage, `0.0.0` scripts are run first, while in `post` and `end`, they are run last. Example: `-- migrations @@ -40,6 +42,8 @@ class MigrationManager(object): |-- 9.0.1.1 # processed only on a 9.0 server | |-- pre-delete_table_z.py | `-- post-clean-data.py + |-- 0.0.0 + | `-- end-invariants.py # processed on all version update `-- foo.py # not processed """ @@ -86,7 +90,7 @@ class MigrationManager(object): return version # the version number already containt the server version return "%s.%s" % (release.major_version, version) - def _get_migration_versions(pkg): + def _get_migration_versions(pkg, stage): versions = list(set( ver for lv in self.migrations[pkg.name].values() @@ -94,6 +98,13 @@ class MigrationManager(object): if lf )) versions.sort(key=lambda k: parse_version(convert_version(k))) + if "0.0.0" in versions: + # reorder versions + versions.remove("0.0.0") + if stage == "pre": + versions.insert(0, "0.0.0") + else: + versions.append("0.0.0") return versions def _get_migration_files(pkg, version, stage): @@ -120,10 +131,11 @@ class MigrationManager(object): parsed_installed_version = parse_version(installed_version) current_version = parse_version(convert_version(pkg.data['version'])) - versions = _get_migration_versions(pkg) + versions = _get_migration_versions(pkg, stage) for version in versions: - if parsed_installed_version < parse_version(convert_version(version)) <= current_version: + if ((version == "0.0.0" and parsed_installed_version < current_version) + or parsed_installed_version < parse_version(convert_version(version)) <= current_version): strfmt = {'addon': pkg.name, 'stage': stage,