erplibre/script/odoo/migration
Mathieu Benoit 00eb0a3c7a [ADD] migration: find the COW copies that drifted from their module view
Third COW incident of this migration, and the first two tools did not cover
it. A copy freezes the module view it came from; version after version the
MODULE view is modernised and the copy is not, until a child xpath lands on an
anchor the copy never had:

  Element '<xpath expr="//head/script[@id='web.layout.odooscript']">'
  cannot be located in parent view

On 14.0 -> 15.0 that was web.layout, copied in the 12.0 era: no id on the
script tag, QWeb still saying t-raw. It had survived only because the 14.0
module xpath carried a fallback — //head/script[@id='…'] | //head/script
[last()] — that 15.0 removed. The breakage was years old; 15.0 merely stopped
hiding it.

The test is DIFFERENTIAL, and it has to be. Resolving a child's xpath against
its parent's own arch proves nothing: Odoo resolves against the COMBINED arch
of the whole chain, so a child of website.layout legitimately targets //header
coming from an ancestor. Measured on the real database, that naive rule
reported 5 copies where only 1 had a problem. Resolving twice — against the
module twin and against the copy — and keeping only what the twin satisfies
and the copy cannot, isolates drift and nothing else.

Two accuracy fixes the real data forced:
  · inactive children are skipped; Odoo never applies them
  · a missing lxml is now a LOUD failure. The first version fell back to
    « everything resolves », so the checker answered « all clean » while
    checking nothing — the worst possible outcome for a checker. Verified: the
    bare system python3 has no lxml, .venv.erplibre does.

--reset copies the module arch over the copy, after saving the previous arch
to a timestamped file and printing the diff, because a copy can hold a real
customisation buried in the drift — on web.layout it was one <meta viewport>
among six differences.

Timing matters: drift only exists once the module views carry the new version,
so run this AFTER OpenUpgrade and BEFORE update_addons_all. Run on the 14.0
database it finds nothing about web.layout, and rightly so — there the module
view says t-raw too.

Verified end to end on a scratch database rebuilt from the real arches:
detection of the exact reported failure, dry-run changing nothing, --apply
resetting it, the backup holding the previous arch, and a clean re-check.
Then across the four migration databases, where it flags two latent drifts
(website_sale.product, website_blog.blog_post_complete) that no version bump
has surfaced yet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-02 03:57:26 -04:00
..
check_cow_views.py [FIX] check_cow_views: detect on arch shape, not on mode 2026-08-01 00:54:44 -04:00
fix_migration_odoo130_to_odoo140.sql [FIX] migration 13->14: hand group_fiscal_year over to om_account_accountant 2026-08-01 04:21:06 -04:00
fix_migration_odoo140_to_odoo150.py [IMP] script: update copyright year to 2026 2026-03-11 23:16:05 -04:00
neutralize_cow_views.py [ADD] migration: neutralize the COW views that would break a version bump 2026-08-01 01:04:38 -04:00
README.base.md [IMP] migration: per-database uninstall list, with a stated reason 2026-07-31 23:25:43 -04:00
README.fr.md [IMP] migration: per-database uninstall list, with a stated reason 2026-07-31 23:25:43 -04:00
README.md [IMP] migration: per-database uninstall list, with a stated reason 2026-07-31 23:25:43 -04:00
reset_stale_cow_views.py [ADD] migration: find the COW copies that drifted from their module view 2026-08-02 03:57:26 -04:00
snapshot_cow_views.py [ADD] migration: snapshot and diff the website COW views at each version bump 2026-08-01 00:58:54 -04:00
uninstall_module_list_odoo140_to_odoo150.txt [IMP] todo support odoo upgrade 2025-10-31 01:43:26 -04:00

Migration

Run this script when doing database migration. Example :

source ./.venv.odoo15.0_python3.8.20/bin/activate && cat ./script/odoo/migration/fix_migration_odoo140_to_odoo150.py | ./odoo15.0/odoo/odoo-bin shell -d DATABASE

Check uninstall_module_list_odoo140_to_odoo150.txt

Module lists to uninstall

Before a version bump, the migration uninstalls the modules listed in uninstall_module_list_odoo<from>_to_odoo<to>.txt. Two locations are read, the private one first, and the results are merged (duplicates dropped):

  1. private/odoo/migration/<database>/uninstall_module_list_odooXX0_to_odooYY0.txt — specific to ONE database, not versioned. Which modules must be dropped depends on the data, so this is where nearly every entry belongs.
  2. script/odoo/migration/uninstall_module_list_odooXX0_to_odooYY0.txt — shared defaults, versioned, valid for every database.

Syntax: one module per line, with a justification after #. Commas and several names per line are accepted; blank lines and full-line comments are ignored. A module without a stated reason is flagged at runtime: removing a module is a decision someone must be able to review later.

queue_job                        # blocks 12->13, trigger queue_job_notify
mgmtsystem_hazard                # not ported to 13.0
web_syncer                       # dropped upstream