Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions docker/scripts/run_odoo_data_workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -3098,20 +3098,19 @@ def _openupgrade_target_version(self) -> str:
def _is_native_20_upgrade(self) -> bool:
return self._openupgrade_target_version().split(".", 1)[0] == "20"

def _uses_openupgrade_framework(self) -> bool:
def _uses_openupgrade_framework(self, *, crossing: bool = False) -> bool:
requested = self.local.openupgrade_load_framework
if requested and self._is_native_20_upgrade():
enabled = requested if requested is not None else crossing or not self._is_native_20_upgrade()
if enabled and self._is_native_20_upgrade():
_, framework = self._resolve_openupgrade_assets(require_framework=True)
try:
manifest = ast.literal_eval((framework / "__manifest__.py").read_text()) if framework is not None else {}
version = manifest.get("version", "")
if not isinstance(version, str) or version.split(".", 1)[0] != self._openupgrade_target_version().split(".", 1)[0]:
raise ValueError("framework target mismatch")
except (OSError, SyntaxError, ValueError, AttributeError) as error:
raise OdooRestorerError(
"Explicit framework loading requires a matching target-series framework manifest."
) from error
return requested if requested is not None else not self._is_native_20_upgrade()
raise OdooRestorerError("Framework loading requires a matching target-series framework manifest.") from error
return enabled

def reset_openupgrade_versions(self) -> list[str]:
if self._is_native_20_upgrade():
Expand Down Expand Up @@ -3148,7 +3147,7 @@ def run_openupgrade(self) -> None:

target_version = self._openupgrade_target_version()
native_20 = self._is_native_20_upgrade()
framework = self._uses_openupgrade_framework()
framework = self._uses_openupgrade_framework(crossing=True)
scripts_paths, _ = self._resolve_openupgrade_assets(require_framework=framework)
if target_version:
self.os_env["OPENUPGRADE_TARGET_VERSION"] = target_version
Expand Down
10 changes: 6 additions & 4 deletions docs/tooling/workspace-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ Notes
authenticates nothing, and Odoo's own neutralize keeps it too.
- For an OpenUpgrade target in major 20, selected from the explicit target
or `ODOO_VERSION`, the existing packaged runner
uses native `base,web` loading and selects its SQL-only
loads `base,web,openupgrade_framework` and selects its SQL-only
`prepare_core_references_20.py` with native `--pre-upgrade-scripts`.
Explicit `ODOO_INSTALL_MODULES` (comma- or colon-separated) selects initial
installs with `--init` in the same invocation as `--update all`, so their
Expand All @@ -646,16 +646,18 @@ Notes
selection during OpenUpgrade. The later restore install phase cannot
substitute for an initial migration ownership handoff.
It retains the discovered upgrade roots; it does not load the Odoo 19
OpenUpgrade framework or reset module states or versions. Subsequent addon
maintenance and release-plan shells also skip that framework. Other targets
OpenUpgrade framework or reset module states or versions. Supply the matching
upstream20 framework in the artifact inputs. Subsequent addon
maintenance and release-plan shells skip it unless explicitly requested. Other targets
retain their existing OpenUpgrade selection. Native 20 rejects
`--reset-versions` before asset discovery or database access; run it without
that flag to preserve the installed versions.
`OPENUPGRADE_LOAD_FRAMEWORK=true` explicitly loads an available framework
for major20 too, including subsequent addon commands. Supply the matching
upstream20 source first in `ODOO_ADDONS_PATH`; its manifest must match the
selected target series. This does not convert a19
framework into a20 framework. Unset keeps the existing selection above.
framework into a20 framework. `OPENUPGRADE_LOAD_FRAMEWORK=false` selects an
explicit framework-free pass; unset loads the framework during the crossing.
For a disposable saved19-to20 diagnostic, set
`ODOO_MIGRATION_DIAGNOSTIC_REPORT` to a private JSONL report path, with
`ODOO_COPY_PURPOSE=migration`, `PLATFORM_INSTANCE=rehearsal` and target20.0.
Expand Down
10 changes: 7 additions & 3 deletions tests/test_odoo_data_workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,7 @@ def test_isolated_upgrade_and_module_commands_prepare_before_starting_odoo(self)
settings = self._local_settings()
settings.openupgrade_enabled = True
settings.openupgrade_target_version = "20.0"
settings.openupgrade_load_framework = False
settings.install_modules = "replacement"
settings.copy_purpose = "migration"
runner = odoo_data_workflows.OdooDataWorkflowRunner(settings, upstream=None, env_file=None)
Expand Down Expand Up @@ -829,10 +830,11 @@ def test_isolated_upgrade_and_module_commands_prepare_before_starting_odoo(self)
operation()
execute.assert_not_called()

def test_native_20_uses_migration_roots_without_requiring_the_legacy_framework(self) -> None:
def test_explicit_framework_opt_out_keeps_native_20_migration_roots(self) -> None:
settings = self._local_settings()
settings.openupgrade_enabled = True
settings.openupgrade_target_version = "20.0"
settings.openupgrade_load_framework = False
runner = odoo_data_workflows.OdooDataWorkflowRunner(settings, upstream=None, env_file=None)
with TemporaryDirectory() as directory:
root = Path(directory)
Expand All @@ -852,6 +854,7 @@ def test_native_20_uses_migration_roots_without_requiring_the_legacy_framework(s
self.assertEqual(Path(selected_roots[0]), (checkout / "src").resolve())
selected_modules = {module for path in selected_roots for module in runner._collect_openupgrade_modules(Path(path))}
self.assertIn("mail", selected_modules)
settings.openupgrade_load_framework = True
settings.openupgrade_target_version = "19.0"
with self.assertRaises(odoo_data_workflows.OdooRestorerError):
runner.run_openupgrade()
Expand All @@ -875,6 +878,7 @@ def test_native_20_selects_only_declared_initial_installs_alongside_update_all(s
settings.openupgrade_target_version = target
settings.odoo_version = runtime
settings.install_modules = declaration
settings.openupgrade_load_framework = False
runner = odoo_data_workflows.OdooDataWorkflowRunner(settings, upstream=None, env_file=None)
with (
patch.object(runner, "_resolve_openupgrade_assets", return_value=([Path("/scripts")], None)),
Expand All @@ -889,11 +893,11 @@ def test_native_20_selects_only_declared_initial_installs_alongside_update_all(s
self.assertNotIn("--init", command)
self.assertEqual(command[command.index("--update") + 1], "all")

def test_explicit_framework_load_applies_to_native_20_and_requires_its_source(self) -> None:
def test_default_framework_load_applies_to_native_20_and_rejects_a_19_framework(self) -> None:
settings = self._local_settings()
settings.openupgrade_enabled = True
settings.openupgrade_target_version = "20.0"
settings.openupgrade_load_framework = True
settings.openupgrade_load_framework = None
runner = odoo_data_workflows.OdooDataWorkflowRunner(settings, upstream=None, env_file=None)
with TemporaryDirectory() as directory:
framework = Path(directory)
Expand Down
Loading