From 69700866a2f2938b8f2d6afd8b6fd23d0c231f6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Thu, 31 Aug 2023 12:25:20 +0200 Subject: [PATCH 01/50] Add 'odoo_repository_migration' Module to manage data regarding the migration of modules from one branch to another: - what has to be migrated - migration PR that could be reviewed - commits/PRs present on source branch but not on target branch --- odoo_repository_migration/__init__.py | 2 + odoo_repository_migration/__manifest__.py | 29 ++++ odoo_repository_migration/data/queue_job.xml | 18 +++ odoo_repository_migration/hooks.py | 14 ++ odoo_repository_migration/models/__init__.py | 4 + .../models/odoo_migration_path.py | 40 +++++ .../models/odoo_module_branch.py | 14 ++ .../models/odoo_module_branch_migration.py | 142 ++++++++++++++++++ .../models/odoo_repository.py | 71 +++++++++ .../security/ir.model.access.csv | 4 + odoo_repository_migration/utils/__init__.py | 0 odoo_repository_migration/utils/scanner.py | 79 ++++++++++ .../views/odoo_migration_path.xml | 43 ++++++ .../views/odoo_module_branch.xml | 39 +++++ .../views/odoo_module_branch_migration.xml | 100 ++++++++++++ .../views/odoo_repository.xml | 17 +++ 16 files changed, 616 insertions(+) create mode 100644 odoo_repository_migration/__init__.py create mode 100644 odoo_repository_migration/__manifest__.py create mode 100644 odoo_repository_migration/data/queue_job.xml create mode 100644 odoo_repository_migration/hooks.py create mode 100644 odoo_repository_migration/models/__init__.py create mode 100644 odoo_repository_migration/models/odoo_migration_path.py create mode 100644 odoo_repository_migration/models/odoo_module_branch.py create mode 100644 odoo_repository_migration/models/odoo_module_branch_migration.py create mode 100644 odoo_repository_migration/models/odoo_repository.py create mode 100644 odoo_repository_migration/security/ir.model.access.csv create mode 100644 odoo_repository_migration/utils/__init__.py create mode 100644 odoo_repository_migration/utils/scanner.py create mode 100644 odoo_repository_migration/views/odoo_migration_path.xml create mode 100644 odoo_repository_migration/views/odoo_module_branch.xml create mode 100644 odoo_repository_migration/views/odoo_module_branch_migration.xml create mode 100644 odoo_repository_migration/views/odoo_repository.xml diff --git a/odoo_repository_migration/__init__.py b/odoo_repository_migration/__init__.py new file mode 100644 index 00000000..4e97e1b8 --- /dev/null +++ b/odoo_repository_migration/__init__.py @@ -0,0 +1,2 @@ +from . import models +from .hooks import update_oca_repositories diff --git a/odoo_repository_migration/__manifest__.py b/odoo_repository_migration/__manifest__.py new file mode 100644 index 00000000..e82f6c4d --- /dev/null +++ b/odoo_repository_migration/__manifest__.py @@ -0,0 +1,29 @@ +# Copyright 2023 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) +{ + "name": "Odoo Repository Migration Data", + "summary": "Collect modules migration data for Odoo Repositories.", + "version": "16.0.1.0.0", + "category": "Tools", + "author": "Camptocamp, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/TODO", + "data": [ + "security/ir.model.access.csv", + "data/queue_job.xml", + "views/odoo_migration_path.xml", + "views/odoo_module_branch.xml", + "views/odoo_module_branch_migration.xml", + "views/odoo_repository.xml", + ], + "installable": True, + "depends": [ + "odoo_repository", + ], + "external_dependencies": { + "python": [ + "oca-port", + ], + }, + "license": "AGPL-3", + "post_init_hook": "update_oca_repositories", +} diff --git a/odoo_repository_migration/data/queue_job.xml b/odoo_repository_migration/data/queue_job.xml new file mode 100644 index 00000000..1d4200da --- /dev/null +++ b/odoo_repository_migration/data/queue_job.xml @@ -0,0 +1,18 @@ + + + + + + odoo_repository_scan_migration + + + + + + _scan_migration_data + + + + + diff --git a/odoo_repository_migration/hooks.py b/odoo_repository_migration/hooks.py new file mode 100644 index 00000000..d95987f0 --- /dev/null +++ b/odoo_repository_migration/hooks.py @@ -0,0 +1,14 @@ +# Copyright 2023 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo import api, SUPERUSER_ID + + +def update_oca_repositories(cr, registry): + """Configure OCA repositories to collect migration data.""" + env = api.Environment(cr, SUPERUSER_ID, {}) + org = env["odoo.repository.org"].search([("name", "=", "OCA")]) + if org: + repositories = env["odoo.repository"].with_context( + active_test=False).search([("org_id", "=", org.id)]) + repositories.write({"collect_migration_data": True}) diff --git a/odoo_repository_migration/models/__init__.py b/odoo_repository_migration/models/__init__.py new file mode 100644 index 00000000..db7baee9 --- /dev/null +++ b/odoo_repository_migration/models/__init__.py @@ -0,0 +1,4 @@ +from . import odoo_migration_path +from . import odoo_module_branch_migration +from . import odoo_module_branch +from . import odoo_repository diff --git a/odoo_repository_migration/models/odoo_migration_path.py b/odoo_repository_migration/models/odoo_migration_path.py new file mode 100644 index 00000000..34bfbe0d --- /dev/null +++ b/odoo_repository_migration/models/odoo_migration_path.py @@ -0,0 +1,40 @@ +# Copyright 2023 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo import api, fields, models + + +class OdooMigrationPath(models.Model): + _name = "odoo.migration.path" + _description = "Define a migration path (from one branch to another)" + _order = "name" + + name = fields.Char(compute="_compute_name", store=True) + active = fields.Boolean(default=True) + source_branch_id = fields.Many2one( + comodel_name="odoo.branch", + ondelete="cascade", + domain=[("odoo_version", "=", True)], + required=True, + ) + target_branch_id = fields.Many2one( + comodel_name="odoo.branch", + ondelete="cascade", + domain=[("odoo_version", "=", True)], + required=True, + ) + + _sql_constraints = [ + ( + "migration_path_uniq", + "UNIQUE (source_branch_id, target_branch_id)", + "This migration path already exists." + ), + ] + + @api.depends("source_branch_id.name", "target_branch_id.name") + def _compute_name(self): + for rec in self: + rec.name = ( + f"{rec.source_branch_id.name} -> {rec.target_branch_id.name}" + ) diff --git a/odoo_repository_migration/models/odoo_module_branch.py b/odoo_repository_migration/models/odoo_module_branch.py new file mode 100644 index 00000000..18dd9ca7 --- /dev/null +++ b/odoo_repository_migration/models/odoo_module_branch.py @@ -0,0 +1,14 @@ +# Copyright 2023 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo import fields, models + + +class OdooModuleBranch(models.Model): + _inherit = "odoo.module.branch" + + migration_ids = fields.One2many( + comodel_name="odoo.module.branch.migration", + inverse_name="module_branch_id", + string="Migrations", + ) diff --git a/odoo_repository_migration/models/odoo_module_branch_migration.py b/odoo_repository_migration/models/odoo_module_branch_migration.py new file mode 100644 index 00000000..85d3e978 --- /dev/null +++ b/odoo_repository_migration/models/odoo_module_branch_migration.py @@ -0,0 +1,142 @@ +# Copyright 2023 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +import pprint + +from odoo import api, fields, models + + +class OdooModuleBranchMigration(models.Model): + _name = "odoo.module.branch.migration" + _description = "Migration data for a module of a given branch." + _order = "display_name" + + display_name = fields.Char(compute="_compute_display_name", store=True) + module_branch_id = fields.Many2one( + comodel_name="odoo.module.branch", + ondelete="cascade", + string="Module", + required=True, + index=True, + ) + module_id = fields.Many2one( + related="module_branch_id.module_id", + store=True, + index=True, + ) + org_id = fields.Many2one(related="module_branch_id.org_id", store=True) + repository_id = fields.Many2one( + related="module_branch_id.repository_id", + store=True, + ondelete="cascade", + ) + migration_path_id = fields.Many2one( + comodel_name="odoo.migration.path", + ondelete="cascade", + required=True, + index=True, + ) + source_branch_id = fields.Many2one( + related="migration_path_id.source_branch_id", + store=True, + index=True, + ) + target_branch_id = fields.Many2one( + related="migration_path_id.target_branch_id", + store=True, + index=True, + ) + author_ids = fields.Many2many(related="module_branch_id.author_ids") + maintainer_ids = fields.Many2many(related="module_branch_id.maintainer_ids") + process = fields.Char(index=True) + state = fields.Selection( + selection=[ + ("fully_ported", "Fully Ported"), + ("migrate", "To migrate"), + ("port_commits", "Commits to port"), + ("review_migration", "Migration to review"), + ], + string="Migration Status", + compute="_compute_state", + store=True, + index=True, + ) + pr_url = fields.Char( + string="PR URL", + compute="_compute_pr_url", + store=True, + ) + results = fields.Serialized() + results_text = fields.Text(compute="_compute_results_text") + last_source_scanned_commit = fields.Char() + last_target_scanned_commit = fields.Char() + + _sql_constraints = [ + ( + "module_migration_path_uniq", + "UNIQUE (module_branch_id, migration_path_id)", + "This module migration path already exists." + ), + ] + + @api.depends( + "module_branch_id.module_id", + "source_branch_id.name", + "target_branch_id.name", + ) + def _compute_display_name(self): + for rec in self: + rec.display_name = ( + f"{rec.module_branch_id.module_id.name}: " + f"{rec.source_branch_id.name} -> {rec.target_branch_id.name}" + ) + + @api.depends("process", "pr_url") + def _compute_state(self): + for rec in self: + rec.state = rec.process or "fully_ported" + if rec.process == "migrate" and rec.pr_url: + rec.state = "review_migration" + + @api.depends("results") + def _compute_pr_url(self): + for rec in self: + rec.pr_url = rec.results.get("existing_pr", {}).get("url") + + @api.depends("results") + def _compute_results_text(self): + for rec in self: + rec.results_text = pprint.pformat(rec.results) + + @api.model + @api.returns("odoo.module.branch.migration") + def push_scanned_data(self, module_branch_id, data): + migration_path = self.env["odoo.migration.path"].search( + [ + ("source_branch_id", "=", data["source_branch"]), + ("target_branch_id", "=", data["target_branch"]), + ] + ) + values = { + "module_branch_id": module_branch_id, + "migration_path_id": migration_path.id, + "last_source_scanned_commit": data["source_commit"], + "last_target_scanned_commit": data["target_commit"], + } + for key in ("process", "results"): + if data.get(key): + values[key] = data[key] + return self._create_or_update(module_branch_id, migration_path, values) + + def _create_or_update(self, module_branch_id, migration_path, values): + args = [ + ("module_branch_id", "=", module_branch_id), + ("source_branch_id", "=", migration_path.source_branch_id.id), + ("target_branch_id", "=", migration_path.target_branch_id.id), + ] + migration = self.search(args) + if migration: + migration.sudo().write(values) + else: + migration = self.sudo().create(values) + return migration diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py new file mode 100644 index 00000000..161d8560 --- /dev/null +++ b/odoo_repository_migration/models/odoo_repository.py @@ -0,0 +1,71 @@ +# Copyright 2023 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo import fields, models + +from odoo.addons.queue_job.job import identity_exact + +from ..utils.scanner import MigrationScannerOdooEnv + + +class OdooRepository(models.Model): + _inherit = "odoo.repository" + + collect_migration_data = fields.Boolean( + string="Collect migration data", + help=( + "Collect migration data based on the configured migration paths." + ), + default=False, + ) + + def _reset_scanned_commits(self): + res = super()._reset_scanned_commits() + self.branch_ids.module_ids.migration_ids.sudo().write( + { + "last_source_scanned_commit": False, + "last_target_scanned_commit": False, + } + ) + return res + + def _create_jobs(self, branches): + jobs = super()._create_jobs(branches) + # Check if the addons_paths are compatible with 'oca_port' + if not self.collect_migration_data: + return jobs + # Override to run the MigrationScanner once all branches are scanned + migration_paths = self.env["odoo.migration.path"].search([]) + for rec in migration_paths: + migration_path = ( + rec.source_branch_id.name, + rec.target_branch_id.name + ) + delayable = self.delayable( + description=( + f"Collect {self.display_name} " + f"{' > '.join(migration_path)} migration data" + ), + identity_key=identity_exact + ) + job = delayable._scan_migration_data(migration_path) + jobs.append(job) + return jobs + + def _scan_migration_data(self, migration_path): + """Scan repository branches to collect modules migration data.""" + params = self._prepare_migration_scanner_parameters(migration_path) + scanner = MigrationScannerOdooEnv(**params) + return scanner.scan() + + def _prepare_migration_scanner_parameters(self, migration_path): + key = self._repositories_path_key + repositories_path = self.env["ir.config_parameter"].get_param(key) + return { + "org": self.org_id.name, + "name": self.name, + "clone_url": self.clone_url, + "migration_paths": [migration_path], + "repositories_path": repositories_path, + "env": self.env + } diff --git a/odoo_repository_migration/security/ir.model.access.csv b/odoo_repository_migration/security/ir.model.access.csv new file mode 100644 index 00000000..41e6e372 --- /dev/null +++ b/odoo_repository_migration/security/ir.model.access.csv @@ -0,0 +1,4 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_odoo_migration_path_user,odoo_migration_path_user,model_odoo_migration_path,base.group_user,1,0,0,0 +access_odoo_migration_path_manager,odoo_migration_path_manager,model_odoo_migration_path,base.group_system,1,0,1,1 +access_odoo_module_branch_migration_user,odoo_module_branch_migration_user,model_odoo_module_branch_migration,base.group_user,1,0,0,0 diff --git a/odoo_repository_migration/utils/__init__.py b/odoo_repository_migration/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/odoo_repository_migration/utils/scanner.py b/odoo_repository_migration/utils/scanner.py new file mode 100644 index 00000000..c9e11485 --- /dev/null +++ b/odoo_repository_migration/utils/scanner.py @@ -0,0 +1,79 @@ +# Copyright 2023 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo.addons.odoo_repository.lib.scanner import MigrationScanner + + +class MigrationScannerOdooEnv(MigrationScanner): + """MigrationScanner running on the same server than Odoo. + + This class takes an additional `env` parameter (`odoo.api.Environment`) + used to request Odoo, and implement required methods to use it. + """ + + def __init__(self, *args, **kwargs): + if kwargs.get("env"): + self.env = kwargs.pop("env") + super().__init__(*args, **kwargs) + + def _get_odoo_repository_id(self) -> int: + return self.env["odoo.repository"].search( + [("name", "=", self.name), ("org_id", "=", self.org)] + ).id + + def _get_odoo_repository_branches(self, repo_id) -> list[str]: + args = [ + ("repository_id", "=", repo_id), + ("branch_id", "in", self.branches), + ] + repo_branches = self.env["odoo.repository.branch"].search(args) + return repo_branches.mapped("branch_id.name") + + def _get_odoo_migration_paths(self, branches: list[str]) -> list[tuple[str]]: + args = [ + ("source_branch_id", "in", branches), + ("target_branch_id", "in", branches), + ] + migration_paths = self.env["odoo.migration.path"].search(args) + return [ + (mp.source_branch_id.name, mp.target_branch_id.name) + for mp in migration_paths + ] + + def _get_odoo_module_branch_id(self, module: str, branch: str) -> int: + args = [ + ("module_id", "=", module), + ("branch_id", "=", branch), + ] + return self.env["odoo.module.branch"].search(args).id + + def _get_odoo_module_branch_migration_id( + self, module_branch_id: int, source_branch: str, target_branch: str) -> int: + args = [ + ("module_branch_id", "=", module_branch_id), + ("source_branch_id", "=", source_branch), + ("target_branch_id", "=", target_branch), + ] + migration = self.env["odoo.module.branch.migration"].search(args) + if migration: + return migration.id + + def _get_odoo_module_branch_migration_data( + self, module: str, source_branch: str, target_branch: str) -> dict: + args = [ + ("module_id", "=", module), + ("source_branch_id", "=", source_branch), + ("target_branch_id", "=", target_branch), + ] + migration = self.env["odoo.module.branch.migration"].search(args) + if migration: + return migration.read()[0] + return {} + + def _push_scanned_data(self, module_branch_id: int, data: dict): + res = self.env["odoo.module.branch.migration"].push_scanned_data( + module_branch_id, data + ) + # Commit after each scan + self.env.cr.commit() + return res diff --git a/odoo_repository_migration/views/odoo_migration_path.xml b/odoo_repository_migration/views/odoo_migration_path.xml new file mode 100644 index 00000000..fc49e7e1 --- /dev/null +++ b/odoo_repository_migration/views/odoo_migration_path.xml @@ -0,0 +1,43 @@ + + + + + + odoo.migration.path.form + odoo.migration.path + +
+ + + + + + +
+
+
+ + + odoo.migration.path.tree + odoo.migration.path + + + + + + + + + + Migration Paths + ir.actions.act_window + odoo.migration.path + + + + + +
diff --git a/odoo_repository_migration/views/odoo_module_branch.xml b/odoo_repository_migration/views/odoo_module_branch.xml new file mode 100644 index 00000000..9e6ca821 --- /dev/null +++ b/odoo_repository_migration/views/odoo_module_branch.xml @@ -0,0 +1,39 @@ + + + + + + odoo.module.branch.form.inherit + odoo.module.branch + + + + + + + + + + + + + + + + + + odoo.module.branch.search.inherit + odoo.module.branch + + + + + + + + + + diff --git a/odoo_repository_migration/views/odoo_module_branch_migration.xml b/odoo_repository_migration/views/odoo_module_branch_migration.xml new file mode 100644 index 00000000..dc2d529b --- /dev/null +++ b/odoo_repository_migration/views/odoo_module_branch_migration.xml @@ -0,0 +1,100 @@ + + + + + + odoo.module.branch.migration.form + odoo.module.branch.migration + +
+ +
+

+
+ + + + + + + + + + + + +
+
+
+
+ + + odoo.module.branch.migration.tree + odoo.module.branch.migration + + + + + + + + + + + + + odoo.module.branch.migration.search + odoo.module.branch.migration + search + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Migrations + ir.actions.act_window + odoo.module.branch.migration + + + + + +
diff --git a/odoo_repository_migration/views/odoo_repository.xml b/odoo_repository_migration/views/odoo_repository.xml new file mode 100644 index 00000000..8a2c0482 --- /dev/null +++ b/odoo_repository_migration/views/odoo_repository.xml @@ -0,0 +1,17 @@ + + + + + + odoo.repository.form.inherit + odoo.repository + + + + + + + + + From d2f5a4b2354ddc3dcff0325517e3c4a7e7a8f96b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Tue, 10 Oct 2023 18:39:28 +0200 Subject: [PATCH 02/50] odoo_repository: add settings panel And handle GitHub token. --- odoo_repository_migration/models/odoo_repository.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py index 161d8560..b338d382 100644 --- a/odoo_repository_migration/models/odoo_repository.py +++ b/odoo_repository_migration/models/odoo_repository.py @@ -1,6 +1,8 @@ # Copyright 2023 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) +import os + from odoo import fields, models from odoo.addons.queue_job.job import identity_exact @@ -59,13 +61,19 @@ def _scan_migration_data(self, migration_path): return scanner.scan() def _prepare_migration_scanner_parameters(self, migration_path): - key = self._repositories_path_key - repositories_path = self.env["ir.config_parameter"].get_param(key) + ir_config = self.env["ir.config_parameter"] + repositories_path = ir_config.get_param(self._repositories_path_key) + github_token = ir_config.get_param( + "odoo_repository_github_token", + os.environ.get("GITHUB_TOKEN") + ) return { "org": self.org_id.name, "name": self.name, "clone_url": self.clone_url, "migration_paths": [migration_path], "repositories_path": repositories_path, + "ssh_key": self.ssh_key_id.private_key, + "github_token": github_token, "env": self.env } From 9311f4c154b8da88c84d630925ab01c9f86587fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Fri, 3 Nov 2023 12:13:31 +0100 Subject: [PATCH 03/50] Apply pre-commit --- odoo_repository_migration/README.rst | 61 +++ odoo_repository_migration/__manifest__.py | 2 +- odoo_repository_migration/data/queue_job.xml | 7 +- odoo_repository_migration/hooks.py | 9 +- .../models/odoo_migration_path.py | 6 +- .../models/odoo_module_branch_migration.py | 2 +- .../models/odoo_repository.py | 16 +- .../readme/CONTRIBUTORS.rst | 2 + .../readme/DESCRIPTION.rst | 1 + .../static/description/index.html | 417 ++++++++++++++++++ odoo_repository_migration/utils/scanner.py | 16 +- .../views/odoo_migration_path.xml | 20 +- .../views/odoo_module_branch.xml | 26 +- .../views/odoo_module_branch_migration.xml | 135 +++--- .../views/odoo_repository.xml | 6 +- 15 files changed, 626 insertions(+), 100 deletions(-) create mode 100644 odoo_repository_migration/README.rst create mode 100644 odoo_repository_migration/readme/CONTRIBUTORS.rst create mode 100644 odoo_repository_migration/readme/DESCRIPTION.rst create mode 100644 odoo_repository_migration/static/description/index.html diff --git a/odoo_repository_migration/README.rst b/odoo_repository_migration/README.rst new file mode 100644 index 00000000..cafdf9b9 --- /dev/null +++ b/odoo_repository_migration/README.rst @@ -0,0 +1,61 @@ +============================== +Odoo Repository Migration Data +============================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:4705947f581f1953f9c146b61253c9ebd83975867442c894ece00ac3c5f142e0 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-camptocamp%2Fodoo--repository-lightgray.png?logo=github + :target: https://github.com/camptocamp/odoo-repository/tree/16.0/odoo_repository_migration + :alt: camptocamp/odoo-repository + +|badge1| |badge2| |badge3| + +This module collects modules migration data from Odoo repositories. + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Camptocamp + +Contributors +~~~~~~~~~~~~ + +* Camptocamp + * Sébastien Alix + +Maintainers +~~~~~~~~~~~ + +This module is part of the `camptocamp/odoo-repository `_ project on GitHub. + +You are welcome to contribute. diff --git a/odoo_repository_migration/__manifest__.py b/odoo_repository_migration/__manifest__.py index e82f6c4d..46cbf98a 100644 --- a/odoo_repository_migration/__manifest__.py +++ b/odoo_repository_migration/__manifest__.py @@ -6,7 +6,7 @@ "version": "16.0.1.0.0", "category": "Tools", "author": "Camptocamp, Odoo Community Association (OCA)", - "website": "https://github.com/OCA/TODO", + "website": "https://github.com/camptocamp/odoo-repository", "data": [ "security/ir.model.access.csv", "data/queue_job.xml", diff --git a/odoo_repository_migration/data/queue_job.xml b/odoo_repository_migration/data/queue_job.xml index 1d4200da..d3c25e06 100644 --- a/odoo_repository_migration/data/queue_job.xml +++ b/odoo_repository_migration/data/queue_job.xml @@ -1,4 +1,4 @@ - + @@ -8,7 +8,10 @@ - + _scan_migration_data diff --git a/odoo_repository_migration/hooks.py b/odoo_repository_migration/hooks.py index d95987f0..ee035c26 100644 --- a/odoo_repository_migration/hooks.py +++ b/odoo_repository_migration/hooks.py @@ -1,7 +1,7 @@ # Copyright 2023 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) -from odoo import api, SUPERUSER_ID +from odoo import SUPERUSER_ID, api def update_oca_repositories(cr, registry): @@ -9,6 +9,9 @@ def update_oca_repositories(cr, registry): env = api.Environment(cr, SUPERUSER_ID, {}) org = env["odoo.repository.org"].search([("name", "=", "OCA")]) if org: - repositories = env["odoo.repository"].with_context( - active_test=False).search([("org_id", "=", org.id)]) + repositories = ( + env["odoo.repository"] + .with_context(active_test=False) + .search([("org_id", "=", org.id)]) + ) repositories.write({"collect_migration_data": True}) diff --git a/odoo_repository_migration/models/odoo_migration_path.py b/odoo_repository_migration/models/odoo_migration_path.py index 34bfbe0d..2f15433c 100644 --- a/odoo_repository_migration/models/odoo_migration_path.py +++ b/odoo_repository_migration/models/odoo_migration_path.py @@ -28,13 +28,11 @@ class OdooMigrationPath(models.Model): ( "migration_path_uniq", "UNIQUE (source_branch_id, target_branch_id)", - "This migration path already exists." + "This migration path already exists.", ), ] @api.depends("source_branch_id.name", "target_branch_id.name") def _compute_name(self): for rec in self: - rec.name = ( - f"{rec.source_branch_id.name} -> {rec.target_branch_id.name}" - ) + rec.name = f"{rec.source_branch_id.name} -> {rec.target_branch_id.name}" diff --git a/odoo_repository_migration/models/odoo_module_branch_migration.py b/odoo_repository_migration/models/odoo_module_branch_migration.py index 85d3e978..b5819583 100644 --- a/odoo_repository_migration/models/odoo_module_branch_migration.py +++ b/odoo_repository_migration/models/odoo_module_branch_migration.py @@ -75,7 +75,7 @@ class OdooModuleBranchMigration(models.Model): ( "module_migration_path_uniq", "UNIQUE (module_branch_id, migration_path_id)", - "This module migration path already exists." + "This module migration path already exists.", ), ] diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py index b338d382..deee9437 100644 --- a/odoo_repository_migration/models/odoo_repository.py +++ b/odoo_repository_migration/models/odoo_repository.py @@ -15,9 +15,7 @@ class OdooRepository(models.Model): collect_migration_data = fields.Boolean( string="Collect migration data", - help=( - "Collect migration data based on the configured migration paths." - ), + help=("Collect migration data based on the configured migration paths."), default=False, ) @@ -39,16 +37,13 @@ def _create_jobs(self, branches): # Override to run the MigrationScanner once all branches are scanned migration_paths = self.env["odoo.migration.path"].search([]) for rec in migration_paths: - migration_path = ( - rec.source_branch_id.name, - rec.target_branch_id.name - ) + migration_path = (rec.source_branch_id.name, rec.target_branch_id.name) delayable = self.delayable( description=( f"Collect {self.display_name} " f"{' > '.join(migration_path)} migration data" ), - identity_key=identity_exact + identity_key=identity_exact, ) job = delayable._scan_migration_data(migration_path) jobs.append(job) @@ -64,8 +59,7 @@ def _prepare_migration_scanner_parameters(self, migration_path): ir_config = self.env["ir.config_parameter"] repositories_path = ir_config.get_param(self._repositories_path_key) github_token = ir_config.get_param( - "odoo_repository_github_token", - os.environ.get("GITHUB_TOKEN") + "odoo_repository_github_token", os.environ.get("GITHUB_TOKEN") ) return { "org": self.org_id.name, @@ -75,5 +69,5 @@ def _prepare_migration_scanner_parameters(self, migration_path): "repositories_path": repositories_path, "ssh_key": self.ssh_key_id.private_key, "github_token": github_token, - "env": self.env + "env": self.env, } diff --git a/odoo_repository_migration/readme/CONTRIBUTORS.rst b/odoo_repository_migration/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..a0c91e35 --- /dev/null +++ b/odoo_repository_migration/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Camptocamp + * Sébastien Alix diff --git a/odoo_repository_migration/readme/DESCRIPTION.rst b/odoo_repository_migration/readme/DESCRIPTION.rst new file mode 100644 index 00000000..fa0b3fab --- /dev/null +++ b/odoo_repository_migration/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module collects modules migration data from Odoo repositories. diff --git a/odoo_repository_migration/static/description/index.html b/odoo_repository_migration/static/description/index.html new file mode 100644 index 00000000..cc60c0b7 --- /dev/null +++ b/odoo_repository_migration/static/description/index.html @@ -0,0 +1,417 @@ + + + + + + +Odoo Repository Migration Data + + + +
+

Odoo Repository Migration Data

+ + +

Beta License: AGPL-3 camptocamp/odoo-repository

+

This module collects modules migration data from Odoo repositories.

+

Table of contents

+ +
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Camptocamp
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is part of the camptocamp/odoo-repository project on GitHub.

+

You are welcome to contribute.

+
+
+
+ + diff --git a/odoo_repository_migration/utils/scanner.py b/odoo_repository_migration/utils/scanner.py index c9e11485..e95a4dd3 100644 --- a/odoo_repository_migration/utils/scanner.py +++ b/odoo_repository_migration/utils/scanner.py @@ -17,9 +17,11 @@ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def _get_odoo_repository_id(self) -> int: - return self.env["odoo.repository"].search( - [("name", "=", self.name), ("org_id", "=", self.org)] - ).id + return ( + self.env["odoo.repository"] + .search([("name", "=", self.name), ("org_id", "=", self.org)]) + .id + ) def _get_odoo_repository_branches(self, repo_id) -> list[str]: args = [ @@ -48,7 +50,8 @@ def _get_odoo_module_branch_id(self, module: str, branch: str) -> int: return self.env["odoo.module.branch"].search(args).id def _get_odoo_module_branch_migration_id( - self, module_branch_id: int, source_branch: str, target_branch: str) -> int: + self, module_branch_id: int, source_branch: str, target_branch: str + ) -> int: args = [ ("module_branch_id", "=", module_branch_id), ("source_branch_id", "=", source_branch), @@ -59,7 +62,8 @@ def _get_odoo_module_branch_migration_id( return migration.id def _get_odoo_module_branch_migration_data( - self, module: str, source_branch: str, target_branch: str) -> dict: + self, module: str, source_branch: str, target_branch: str + ) -> dict: args = [ ("module_id", "=", module), ("source_branch_id", "=", source_branch), @@ -75,5 +79,5 @@ def _push_scanned_data(self, module_branch_id: int, data: dict): module_branch_id, data ) # Commit after each scan - self.env.cr.commit() + self.env.cr.commit() # pylint: disable=invalid-commit return res diff --git a/odoo_repository_migration/views/odoo_migration_path.xml b/odoo_repository_migration/views/odoo_migration_path.xml index fc49e7e1..ff8691ad 100644 --- a/odoo_repository_migration/views/odoo_migration_path.xml +++ b/odoo_repository_migration/views/odoo_migration_path.xml @@ -1,4 +1,4 @@ - + @@ -10,8 +10,8 @@
- - + +
@@ -23,8 +23,8 @@ odoo.migration.path - - + +
@@ -33,11 +33,13 @@ Migration Paths ir.actions.act_window odoo.migration.path - +
- +
diff --git a/odoo_repository_migration/views/odoo_module_branch.xml b/odoo_repository_migration/views/odoo_module_branch.xml index 9e6ca821..d0558fc4 100644 --- a/odoo_repository_migration/views/odoo_module_branch.xml +++ b/odoo_repository_migration/views/odoo_module_branch.xml @@ -1,4 +1,4 @@ - + @@ -6,15 +6,15 @@ odoo.module.branch.form.inherit odoo.module.branch - + - - - + + + @@ -25,13 +25,19 @@ odoo.module.branch.search.inherit odoo.module.branch - + - - + + diff --git a/odoo_repository_migration/views/odoo_module_branch_migration.xml b/odoo_repository_migration/views/odoo_module_branch_migration.xml index dc2d529b..e2ac202f 100644 --- a/odoo_repository_migration/views/odoo_module_branch_migration.xml +++ b/odoo_repository_migration/views/odoo_module_branch_migration.xml @@ -1,4 +1,4 @@ - + @@ -10,19 +10,19 @@
-

+

- - - - - + + + + + - - - + + +
@@ -34,11 +34,11 @@ odoo.module.branch.migration - - - - - + + + + +
@@ -49,38 +49,71 @@ search - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - + + + + + + + @@ -90,11 +123,13 @@ Migrations ir.actions.act_window odoo.module.branch.migration - + - +
diff --git a/odoo_repository_migration/views/odoo_repository.xml b/odoo_repository_migration/views/odoo_repository.xml index 8a2c0482..a8961598 100644 --- a/odoo_repository_migration/views/odoo_repository.xml +++ b/odoo_repository_migration/views/odoo_repository.xml @@ -1,4 +1,4 @@ - + @@ -6,10 +6,10 @@ odoo.repository.form.inherit odoo.repository - + - + From 0e3f4dd2756f6fb058a79f253eba3edf9acff33f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Sat, 4 Nov 2023 11:42:50 +0100 Subject: [PATCH 04/50] odoo_repository_migration: sync data from main node --- .../models/odoo_module_branch.py | 8 ++++ .../models/odoo_module_branch_migration.py | 11 +++++ .../models/odoo_repository.py | 46 ++++++++++++++++++- 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/odoo_repository_migration/models/odoo_module_branch.py b/odoo_repository_migration/models/odoo_module_branch.py index 18dd9ca7..78699a98 100644 --- a/odoo_repository_migration/models/odoo_module_branch.py +++ b/odoo_repository_migration/models/odoo_module_branch.py @@ -12,3 +12,11 @@ class OdooModuleBranch(models.Model): inverse_name="module_branch_id", string="Migrations", ) + + def _to_dict(self): + # Add the migrations data + data = super()._to_dict() + data["migrations"] = [] + for migration in self.migration_ids: + data["migrations"].append(migration._to_dict()) + return data diff --git a/odoo_repository_migration/models/odoo_module_branch_migration.py b/odoo_repository_migration/models/odoo_module_branch_migration.py index b5819583..8a9f1cba 100644 --- a/odoo_repository_migration/models/odoo_module_branch_migration.py +++ b/odoo_repository_migration/models/odoo_module_branch_migration.py @@ -140,3 +140,14 @@ def _create_or_update(self, module_branch_id, migration_path, values): else: migration = self.sudo().create(values) return migration + + def _to_dict(self): + self.ensure_one() + return { + "source_branch": self.source_branch_id.name, + "target_branch": self.target_branch_id.name, + "process": self.process, + "results": self.results, + "last_source_scanned_commit": self.last_source_scanned_commit, + "last_target_scanned_commit": self.last_target_scanned_commit, + } diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py index deee9437..3e61eb9e 100644 --- a/odoo_repository_migration/models/odoo_repository.py +++ b/odoo_repository_migration/models/odoo_repository.py @@ -3,7 +3,7 @@ import os -from odoo import fields, models +from odoo import fields, models, tools from odoo.addons.queue_job.job import identity_exact @@ -71,3 +71,47 @@ def _prepare_migration_scanner_parameters(self, migration_path): "github_token": github_token, "env": self.env, } + + def _prepare_module_branch_values(self, data): + # Handle migration data + values = super()._prepare_module_branch_values(data) + migrations = data.get("migrations", []) + for mig in migrations: + source_branch = self.env["odoo.branch"].search( + [("odoo_version", "=", True), ("name", "=", mig["source_branch"])] + ) + target_branch = self.env["odoo.branch"].search( + [("odoo_version", "=", True), ("name", "=", mig["target_branch"])] + ) + if not source_branch or not target_branch: + # Such branches are not configured on this instance, skip + continue + migration_path = self._get_migration_path( + source_branch.id, target_branch.id + ) + mig_values = { + "migration_path_id": migration_path.id, + "process": mig["process"], + "results": mig["results"], + "last_source_scanned_commit": mig["last_source_scanned_commit"], + "last_target_scanned_commit": mig["last_target_scanned_commit"], + } + values["migration_ids"] = [(0, 0, mig_values)] + return values + + @tools.ormcache("source_branch_id", "target_branch_id") + def _get_migration_path(self, source_branch_id, target_branch_id): + rec = self.env["odoo.migration.path"].search( + [ + ("source_branch_id", "=", source_branch_id), + ("target_branch_id", "=", target_branch_id), + ], + limit=1, + ) + values = { + "source_branch_id": source_branch_id, + "target_branch_id": target_branch_id, + } + if not rec: + rec = self.env["odoo.migration.path"].sudo().create(values) + return rec From 9a4099535337502a963c32e7aea38b9a86885d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Wed, 8 Nov 2023 12:58:20 +0100 Subject: [PATCH 05/50] o_r_migration: default filters for 'Migrations' menu --- .../views/odoo_module_branch_migration.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/odoo_repository_migration/views/odoo_module_branch_migration.xml b/odoo_repository_migration/views/odoo_module_branch_migration.xml index e2ac202f..cad1e2ae 100644 --- a/odoo_repository_migration/views/odoo_module_branch_migration.xml +++ b/odoo_repository_migration/views/odoo_module_branch_migration.xml @@ -124,6 +124,9 @@ ir.actions.act_window odoo.module.branch.migration + {'search_default_group_by_migration_path_id': 1, 'search_default_group_by_state': 2} Date: Wed, 22 Nov 2023 13:29:27 +0100 Subject: [PATCH 06/50] odoo_repository_migration: fix sync data from main node --- .../models/odoo_repository.py | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py index 3e61eb9e..cc86ec12 100644 --- a/odoo_repository_migration/models/odoo_repository.py +++ b/odoo_repository_migration/models/odoo_repository.py @@ -72,10 +72,12 @@ def _prepare_migration_scanner_parameters(self, migration_path): "env": self.env, } - def _prepare_module_branch_values(self, data): + def _pre_create_or_update_module_branch(self, rec, values, raw_data): # Handle migration data - values = super()._prepare_module_branch_values(data) - migrations = data.get("migrations", []) + values = super()._pre_create_or_update_module_branch(rec, values, raw_data) + mig_model = self.env["odoo.module.branch.migration"] + migrations = raw_data.get("migrations", []) + values["migration_ids"] = [] for mig in migrations: source_branch = self.env["odoo.branch"].search( [("odoo_version", "=", True), ("name", "=", mig["source_branch"])] @@ -96,7 +98,20 @@ def _prepare_module_branch_values(self, data): "last_source_scanned_commit": mig["last_source_scanned_commit"], "last_target_scanned_commit": mig["last_target_scanned_commit"], } - values["migration_ids"] = [(0, 0, mig_values)] + # Check if this migration data exists to update it, otherwise create it + mig_rec = None + if rec: + mig_rec = mig_model.search( + [ + ("migration_path_id", "=", migration_path.id), + ("module_branch_id", "=", rec.id), + ], + ) + if mig_rec: + mig_values_ = fields.Command.update(mig_rec.id, mig_values) + else: + mig_values_ = fields.Command.create(mig_values) + values["migration_ids"].append(mig_values_) return values @tools.ormcache("source_branch_id", "target_branch_id") From 6f75e9cf525c787a3993ce2805c54d36ae8dc491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Sun, 26 Nov 2023 11:39:32 +0100 Subject: [PATCH 07/50] odoo_repository: limit the scan/force-scan to selected branches --- .../models/odoo_repository.py | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py index cc86ec12..74ce291e 100644 --- a/odoo_repository_migration/models/odoo_repository.py +++ b/odoo_repository_migration/models/odoo_repository.py @@ -19,9 +19,16 @@ class OdooRepository(models.Model): default=False, ) - def _reset_scanned_commits(self): - res = super()._reset_scanned_commits() - self.branch_ids.module_ids.migration_ids.sudo().write( + def _reset_scanned_commits(self, branches=None): + res = super()._reset_scanned_commits(branches) + if branches is None: + branches = [] + branches_ = ( + self.branch_ids.filtered(lambda br: br.branch_id.name in branches) + if branches + else self.branch_ids + ) + branches_.module_ids.migration_ids.sudo().write( { "last_source_scanned_commit": False, "last_target_scanned_commit": False, @@ -34,8 +41,15 @@ def _create_jobs(self, branches): # Check if the addons_paths are compatible with 'oca_port' if not self.collect_migration_data: return jobs - # Override to run the MigrationScanner once all branches are scanned - migration_paths = self.env["odoo.migration.path"].search([]) + # Override to run the MigrationScanner once branches are scanned + args = [] + if branches: + args = [ + "|", + ("source_branch_id", "in", branches), + ("target_branch_id", "in", branches), + ] + migration_paths = self.env["odoo.migration.path"].search(args) for rec in migration_paths: migration_path = (rec.source_branch_id.name, rec.target_branch_id.name) delayable = self.delayable( From a7f136ac8236ca6d44aabf0c06ee80475d57004c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Mon, 27 Nov 2023 08:18:04 +0100 Subject: [PATCH 08/50] odoo_repository_migration: ctx key to disable MigrationScanner run --- odoo_repository_migration/models/odoo_repository.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py index 74ce291e..34842d00 100644 --- a/odoo_repository_migration/models/odoo_repository.py +++ b/odoo_repository_migration/models/odoo_repository.py @@ -39,7 +39,8 @@ def _reset_scanned_commits(self, branches=None): def _create_jobs(self, branches): jobs = super()._create_jobs(branches) # Check if the addons_paths are compatible with 'oca_port' - if not self.collect_migration_data: + disable_collect = self.env.context.get("disable_collect_migration_data") + if not self.collect_migration_data or disable_collect: return jobs # Override to run the MigrationScanner once branches are scanned args = [] From b20eeac1851cff5354093b496391268aef587049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Thu, 2 May 2024 15:15:43 +0200 Subject: [PATCH 09/50] odoo_repository: handle git authentication with tokens --- odoo_repository_migration/models/odoo_repository.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py index 34842d00..7244e5f0 100644 --- a/odoo_repository_migration/models/odoo_repository.py +++ b/odoo_repository_migration/models/odoo_repository.py @@ -1,7 +1,6 @@ # Copyright 2023 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) -import os from odoo import fields, models, tools @@ -73,17 +72,15 @@ def _scan_migration_data(self, migration_path): def _prepare_migration_scanner_parameters(self, migration_path): ir_config = self.env["ir.config_parameter"] repositories_path = ir_config.get_param(self._repositories_path_key) - github_token = ir_config.get_param( - "odoo_repository_github_token", os.environ.get("GITHUB_TOKEN") - ) return { "org": self.org_id.name, "name": self.name, "clone_url": self.clone_url, "migration_paths": [migration_path], "repositories_path": repositories_path, + "repo_type": self.repo_type, "ssh_key": self.ssh_key_id.private_key, - "github_token": github_token, + "token": self._get_token(), "env": self.env, } From b1bf17b9a0e65f5c5de6f6245a4b9fa1732e6d2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Fri, 10 May 2024 09:51:23 +0200 Subject: [PATCH 10/50] odoo_repository: handle blacklisted modules We do not want to scan some modules and attach them to a repository as while they have the same name among different projects, they do not share the same code and are specific to a project. Such modules are for instance: - studio_customization (generated by Studio in Odoo Enterprise) - server_environment_files (created manually by developers to leverage server_environment module features) --- odoo_repository_migration/utils/scanner.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/odoo_repository_migration/utils/scanner.py b/odoo_repository_migration/utils/scanner.py index e95a4dd3..deddc1d9 100644 --- a/odoo_repository_migration/utils/scanner.py +++ b/odoo_repository_migration/utils/scanner.py @@ -42,6 +42,13 @@ def _get_odoo_migration_paths(self, branches: list[str]) -> list[tuple[str]]: for mp in migration_paths ] + def _is_module_blacklisted(self, module): + return bool( + self.env["odoo.module"].search_count( + [("name", "=", module), ("blacklisted", "=", True)] + ) + ) + def _get_odoo_module_branch_id(self, module: str, branch: str) -> int: args = [ ("module_id", "=", module), From c1520c1367088483261daa94e97c00b68665ef1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Thu, 23 May 2024 18:03:54 +0200 Subject: [PATCH 11/50] odoo_repository_migration: force scan when a migration path is created --- .../models/odoo_migration_path.py | 19 +++++++++++++++++++ .../views/odoo_migration_path.xml | 9 +++++++++ 2 files changed, 28 insertions(+) diff --git a/odoo_repository_migration/models/odoo_migration_path.py b/odoo_repository_migration/models/odoo_migration_path.py index 2f15433c..83cd5190 100644 --- a/odoo_repository_migration/models/odoo_migration_path.py +++ b/odoo_repository_migration/models/odoo_migration_path.py @@ -36,3 +36,22 @@ class OdooMigrationPath(models.Model): def _compute_name(self): for rec in self: rec.name = f"{rec.source_branch_id.name} -> {rec.target_branch_id.name}" + + @api.model_create_multi + def create(self, vals_list): + records = super().create(vals_list) + # Automatically launch a scan on all relevant repositories when a + # migration path is created + if not self.env.context.get("disable_force_scan"): + records.action_force_scan() + return records + + def action_force_scan(self): + """Force the scan of the source branch. + + Scan is done on all related repositories configured to collect migration data. + """ + branches = self.source_branch_id | self.target_branch_id + return branches.repository_branch_ids.filtered( + lambda o: o.repository_id.collect_migration_data + ).action_force_scan() diff --git a/odoo_repository_migration/views/odoo_migration_path.xml b/odoo_repository_migration/views/odoo_migration_path.xml index ff8691ad..b5e52e54 100644 --- a/odoo_repository_migration/views/odoo_migration_path.xml +++ b/odoo_repository_migration/views/odoo_migration_path.xml @@ -8,6 +8,15 @@ odoo.migration.path
+
+
From ac15818537a6143da9eb9f443d1c02c331467f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Wed, 18 Sep 2024 15:36:24 +0200 Subject: [PATCH 12/50] odoo_repository_migration: limit strictly the scan of migration paths through a context key --- odoo_repository_migration/models/odoo_repository.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py index 7244e5f0..9231cdc0 100644 --- a/odoo_repository_migration/models/odoo_repository.py +++ b/odoo_repository_migration/models/odoo_repository.py @@ -44,8 +44,12 @@ def _create_jobs(self, branches): # Override to run the MigrationScanner once branches are scanned args = [] if branches: + # A strict scan of branches avoids unwanted migration scans + # For instance if we are interested only by 14.0 and 17.0 branches, + # this avoids to scan other migration paths like 15.0 -> 17.0 + strict_scan = self.env.context.get("strict_branches_scan") args = [ - "|", + "&" if strict_scan else "|", ("source_branch_id", "in", branches), ("target_branch_id", "in", branches), ] From ea814ba43719a45c0795663230abc558525b2d84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Sun, 22 Sep 2024 17:34:50 +0200 Subject: [PATCH 13/50] odoo_repository: split RepositoryScanner jobs in smaller jobs RepositoryScanner jobs could be quite long to execute on a repository (like 'odoo/odoo'), and depending on your Odoo config or your monitoring tools, such job could get killed before it ends up its work. While there is no issue to get the RepositoryScanner job killed and restarted later, it'll re-analyze the branch to scan to detect again the modules it has to scan, and this process itself could take ages before it re-starts the scan of the modules themselves. This commit is splitting these two tasks: - one job to detect modules to scan for a given repository/branch - one job created for each module to scan All of these jobs are depending on each other so we ensure that they are run sequentially (one branch after another, and one module after another) so only one job is running for a given repository at a time. We also ensure that no more than one job can be spawned by the user from UI. This results in a higher number of jobs, but scanning can be recovered easily. --- .../models/odoo_repository.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py index 9231cdc0..39d74253 100644 --- a/odoo_repository_migration/models/odoo_repository.py +++ b/odoo_repository_migration/models/odoo_repository.py @@ -1,7 +1,6 @@ # Copyright 2023 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) - from odoo import fields, models, tools from odoo.addons.queue_job.job import identity_exact @@ -35,23 +34,29 @@ def _reset_scanned_commits(self, branches=None): ) return res - def _create_jobs(self, branches): - jobs = super()._create_jobs(branches) + def _create_subsequent_jobs(self, branch, next_branches, all_branches, data): + jobs = super()._create_subsequent_jobs( + branch, next_branches, all_branches, data + ) + # Prepare migration scan jobs when its the last repository scan + last_scan = not next_branches + if not last_scan: + return jobs # Check if the addons_paths are compatible with 'oca_port' disable_collect = self.env.context.get("disable_collect_migration_data") if not self.collect_migration_data or disable_collect: return jobs # Override to run the MigrationScanner once branches are scanned args = [] - if branches: + if all_branches: # A strict scan of branches avoids unwanted migration scans # For instance if we are interested only by 14.0 and 17.0 branches, # this avoids to scan other migration paths like 15.0 -> 17.0 strict_scan = self.env.context.get("strict_branches_scan") args = [ "&" if strict_scan else "|", - ("source_branch_id", "in", branches), - ("target_branch_id", "in", branches), + ("source_branch_id", "in", all_branches), + ("target_branch_id", "in", all_branches), ] migration_paths = self.env["odoo.migration.path"].search(args) for rec in migration_paths: From 8db2315325d63b1ce1fde384e4f024df3d556120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Mon, 23 Sep 2024 14:43:24 +0200 Subject: [PATCH 14/50] odoo_repository_migration: split MigrationScanner jobs in smaller jobs MigrationScanner jobs could be quite long to execute on some repositories, and depending on your Odoo config or your monitoring tools, such job could get killed before it ends up its work. This commit is splitting these two tasks: - one job to scan a migration path for a given repository (that will create one job per module needing a migration scan) - one job created for each module to scan Migration scan jobs depends on the last repository scan job, as we need this one to be finished to know the list of modules that would need a migration scan. --- odoo_repository_migration/data/queue_job.xml | 14 ++- .../models/odoo_migration_path.py | 10 +++ .../models/odoo_module_branch.py | 39 +++++++- .../models/odoo_repository.py | 88 ++++++++++++++++--- 4 files changed, 138 insertions(+), 13 deletions(-) diff --git a/odoo_repository_migration/data/queue_job.xml b/odoo_repository_migration/data/queue_job.xml index d3c25e06..448affa1 100644 --- a/odoo_repository_migration/data/queue_job.xml +++ b/odoo_repository_migration/data/queue_job.xml @@ -9,11 +9,21 @@ - _scan_migration_data + _scan_migration_paths + + + + + + + _scan_migration_module diff --git a/odoo_repository_migration/models/odoo_migration_path.py b/odoo_repository_migration/models/odoo_migration_path.py index 83cd5190..605fc423 100644 --- a/odoo_repository_migration/models/odoo_migration_path.py +++ b/odoo_repository_migration/models/odoo_migration_path.py @@ -40,6 +40,16 @@ def _compute_name(self): @api.model_create_multi def create(self, vals_list): records = super().create(vals_list) + # Recompute 'migration_scan' flag on relevant modules + modules = self.env["odoo.module.branch"].search( + [ + "|", + ("branch_id", "in", records.source_branch_id.ids), + ("branch_id", "in", records.target_branch_id.ids), + ] + ) + modules.modified(["last_scanned_commit"]) + modules.flush_recordset(["migration_scan"]) # Automatically launch a scan on all relevant repositories when a # migration path is created if not self.env.context.get("disable_force_scan"): diff --git a/odoo_repository_migration/models/odoo_module_branch.py b/odoo_repository_migration/models/odoo_module_branch.py index 78699a98..544ea666 100644 --- a/odoo_repository_migration/models/odoo_module_branch.py +++ b/odoo_repository_migration/models/odoo_module_branch.py @@ -1,7 +1,7 @@ # Copyright 2023 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) -from odoo import fields, models +from odoo import api, fields, models class OdooModuleBranch(models.Model): @@ -13,6 +13,43 @@ class OdooModuleBranch(models.Model): string="Migrations", ) + migration_scan = fields.Boolean( + compute="_compute_migration_scan", + store=True, + help="Technical field telling if this module is elligible for a migration scan.", + ) + + @api.depends( + "last_scanned_commit", + "migration_ids.last_source_scanned_commit", + ) + def _compute_migration_scan(self): + for rec in self: + # Default repository migration scan policy + rec.migration_scan = rec.repository_id.collect_migration_data + if not rec.migration_scan: + continue + # Repository scan has to be performed first + if not rec.last_scanned_commit: + continue + # Migration scan to do as soon as a migration path is missing + # among existing scans + available_migration_paths = self.env["odoo.migration.path"].search( + [("source_branch_id", "=", rec.branch_id.id)] + ) + scanned_migration_paths = rec.migration_ids.migration_path_id + if available_migration_paths != scanned_migration_paths: + rec.migration_scan = True + continue + # Migration scan to do if last scanned commit doesn't match the last + # migration scan + for migration in rec.migration_ids: + if migration.last_source_scanned_commit != rec.last_scanned_commit: + rec.migration_scan = True + break + # Reaching this point means no scan is required + rec.migration_scan = False + def _to_dict(self): # Add the migrations data data = super()._to_dict() diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py index 39d74253..a0c51213 100644 --- a/odoo_repository_migration/models/odoo_repository.py +++ b/odoo_repository_migration/models/odoo_repository.py @@ -3,6 +3,8 @@ from odoo import fields, models, tools +from odoo.addons.queue_job.delay import chain +from odoo.addons.queue_job.exception import RetryableJobError from odoo.addons.queue_job.job import identity_exact from ..utils.scanner import MigrationScannerOdooEnv @@ -59,33 +61,99 @@ def _create_subsequent_jobs(self, branch, next_branches, all_branches, data): ("target_branch_id", "in", all_branches), ] migration_paths = self.env["odoo.migration.path"].search(args) - for rec in migration_paths: - migration_path = (rec.source_branch_id.name, rec.target_branch_id.name) + # Launch one job for all migration_paths + if migration_paths: + delayable = self.delayable( + description=f"Collect {self.display_name} migration data", + identity_key=identity_exact, + ) + job = delayable._scan_migration_paths(migration_paths.ids) + jobs.append(job) + return jobs + + def _scan_migration_paths(self, migration_path_ids): + """Scan repository branches to collect modules migration data. + + Spawn one job per module to scan. + """ + self.ensure_one() + jobs = [] + migration_paths = ( + self.env["odoo.migration.path"].browse(migration_path_ids).exists() + ) + for migration_path in migration_paths: + modules_to_scan = self._migration_get_modules_to_scan(migration_path) + if modules_to_scan: + jobs.extend( + self._migration_create_jobs_scan_module( + migration_path, modules_to_scan + ) + ) + if jobs: + chain(*jobs).delay() + return True + + def _migration_create_jobs_scan_module(self, migration_path, modules_to_scan): + jobs = [] + mig_path = ( + migration_path.source_branch_id.name, + migration_path.target_branch_id.name, + ) + for module in modules_to_scan: delayable = self.delayable( description=( - f"Collect {self.display_name} " - f"{' > '.join(migration_path)} migration data" + f"Collect {module.name} migration data " f"({' > '.join(mig_path)})" ), identity_key=identity_exact, ) - job = delayable._scan_migration_data(migration_path) + job = delayable._scan_migration_module( + migration_path.id, module.module_id.name + ) jobs.append(job) return jobs - def _scan_migration_data(self, migration_path): - """Scan repository branches to collect modules migration data.""" + def _scan_migration_module(self, migration_path_id, module_name): + """Scan migration path for `module_name`.""" + migration_path = ( + self.env["odoo.migration.path"].browse(migration_path_id).exists() + ) params = self._prepare_migration_scanner_parameters(migration_path) - scanner = MigrationScannerOdooEnv(**params) - return scanner.scan() + try: + scanner = MigrationScannerOdooEnv(**params) + return scanner.scan(modules=[module_name]) + except Exception as exc: + raise RetryableJobError("Scanner error") from exc + + def _migration_get_modules_to_scan(self, migration_path): + """Return `odoo.module.branch` records that need a migration scan.""" + self.ensure_one() + return self.env["odoo.module.branch"].search( + [ + ( + "repository_id", + "=", + self.id, + ), + ("branch_id", "=", migration_path.source_branch_id.id), + ("migration_scan", "=", True), + # Do not scan removed or pending (in PR) modules + ("removed", "=", False), + ("last_scanned_commit", "!=", False), + ] + ) def _prepare_migration_scanner_parameters(self, migration_path): ir_config = self.env["ir.config_parameter"] repositories_path = ir_config.get_param(self._repositories_path_key) + mig_path = ( + migration_path.source_branch_id.name, + migration_path.target_branch_id.name, + ) return { "org": self.org_id.name, "name": self.name, "clone_url": self.clone_url, - "migration_paths": [migration_path], + "migration_path": mig_path, "repositories_path": repositories_path, "repo_type": self.repo_type, "ssh_key": self.ssh_key_id.private_key, From 28f30a2b7b7cd757789b4f4ce9dced8a9ea23fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Fri, 11 Oct 2024 09:15:23 +0200 Subject: [PATCH 15/50] odoo_repository_migration: fix 'push_scanned_data' Once a module is fully ported/migrated on the target branch, the `results` key is empty, as such the state has to be updated to 'Fully Ported'. --- .../models/odoo_module_branch_migration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/odoo_repository_migration/models/odoo_module_branch_migration.py b/odoo_repository_migration/models/odoo_module_branch_migration.py index 8a9f1cba..b12e2c9a 100644 --- a/odoo_repository_migration/models/odoo_module_branch_migration.py +++ b/odoo_repository_migration/models/odoo_module_branch_migration.py @@ -124,7 +124,7 @@ def push_scanned_data(self, module_branch_id, data): "last_target_scanned_commit": data["target_commit"], } for key in ("process", "results"): - if data.get(key): + if key in data: values[key] = data[key] return self._create_or_update(module_branch_id, migration_path, values) From 2c77b50441a520cafbbd19bfa304aaeda231c668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Mon, 14 Oct 2024 16:17:23 +0200 Subject: [PATCH 16/50] odoo_repository_migration: fix 'migration_scan' computation --- odoo_repository_migration/models/odoo_module_branch.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/odoo_repository_migration/models/odoo_module_branch.py b/odoo_repository_migration/models/odoo_module_branch.py index 544ea666..a3e54a6a 100644 --- a/odoo_repository_migration/models/odoo_module_branch.py +++ b/odoo_repository_migration/models/odoo_module_branch.py @@ -37,7 +37,9 @@ def _compute_migration_scan(self): available_migration_paths = self.env["odoo.migration.path"].search( [("source_branch_id", "=", rec.branch_id.id)] ) - scanned_migration_paths = rec.migration_ids.migration_path_id + scanned_migration_paths = rec.migration_ids.migration_path_id.filtered( + "active" + ) if available_migration_paths != scanned_migration_paths: rec.migration_scan = True continue From 51de4639f01adca41065aa8e31648d7f726040f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Thu, 17 Oct 2024 19:43:45 +0200 Subject: [PATCH 17/50] odoo_repository: add User and Manager user groups --- odoo_repository_migration/security/ir.model.access.csv | 6 +++--- odoo_repository_migration/views/odoo_migration_path.xml | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/odoo_repository_migration/security/ir.model.access.csv b/odoo_repository_migration/security/ir.model.access.csv index 41e6e372..7b021329 100644 --- a/odoo_repository_migration/security/ir.model.access.csv +++ b/odoo_repository_migration/security/ir.model.access.csv @@ -1,4 +1,4 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_odoo_migration_path_user,odoo_migration_path_user,model_odoo_migration_path,base.group_user,1,0,0,0 -access_odoo_migration_path_manager,odoo_migration_path_manager,model_odoo_migration_path,base.group_system,1,0,1,1 -access_odoo_module_branch_migration_user,odoo_module_branch_migration_user,model_odoo_module_branch_migration,base.group_user,1,0,0,0 +access_odoo_migration_path_user,odoo_migration_path_user,model_odoo_migration_path,odoo_repository.group_odoo_repository_user,1,0,0,0 +access_odoo_migration_path_manager,odoo_migration_path_manager,model_odoo_migration_path,odoo_repository.group_odoo_repository_manager,1,0,1,1 +access_odoo_module_branch_migration_user,odoo_module_branch_migration_user,model_odoo_module_branch_migration,odoo_repository.group_odoo_repository_user,1,0,0,0 diff --git a/odoo_repository_migration/views/odoo_migration_path.xml b/odoo_repository_migration/views/odoo_migration_path.xml index b5e52e54..151c9c79 100644 --- a/odoo_repository_migration/views/odoo_migration_path.xml +++ b/odoo_repository_migration/views/odoo_migration_path.xml @@ -15,6 +15,7 @@ string="Force Scan" class="btn-secondary" confirm="This operation will restart the scan on all relevant repositories. Are you sure?" + groups="odoo_repository.group_odoo_repository_manager" /> From 4395b167b821e4119fd647f63560ead680b15008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Tue, 29 Oct 2024 17:24:58 +0100 Subject: [PATCH 18/50] odoo_repository: option to force cloned repository name --- odoo_repository_migration/models/odoo_repository.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py index a0c51213..411af9ff 100644 --- a/odoo_repository_migration/models/odoo_repository.py +++ b/odoo_repository_migration/models/odoo_repository.py @@ -158,6 +158,10 @@ def _prepare_migration_scanner_parameters(self, migration_path): "repo_type": self.repo_type, "ssh_key": self.ssh_key_id.private_key, "token": self._get_token(), + "workaround_fs_errors": ( + self.env.company.config_odoo_repository_workaround_fs_errors + ), + "clone_name": self.clone_name, "env": self.env, } From 9488a15aab807c0739a02c980fc69436eff825ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Fri, 18 Oct 2024 14:35:41 +0200 Subject: [PATCH 19/50] [REF] Allow same module name across different repositories This change allows to get a module `x` present in different repositories (unicity constraint on `odoo.module.branch` has changed accordingly). This is useful in case two projects have `x` installed but the code of these modules (that can be different) are hosted in their own project repository. Therefore, the scan of repositories and project modules import have been adapted to fullfil this new possibility. Features: - allows multiple instances of `` records sharing the same module technical name and branch but belonging to different repositories, - repositories have now a new `specific` flag, propagated to their modules.. By default they host generic modules, but project repositories will host specific modules that cannot be shared to other projects, - a generic module cannot depend on a specific module - when importing modules in a project, specific modules of other projects cannot be mapped, - once a specific module is scanned in a project repository, relevant orphaned modules installed in a project will be re-mapped to this newly created specific module, - detect PR only on generic modules (unmerged/pending modules are generic only, specific modules have to be found in project repositories). --- odoo_repository_migration/utils/scanner.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/odoo_repository_migration/utils/scanner.py b/odoo_repository_migration/utils/scanner.py index deddc1d9..994add61 100644 --- a/odoo_repository_migration/utils/scanner.py +++ b/odoo_repository_migration/utils/scanner.py @@ -49,8 +49,9 @@ def _is_module_blacklisted(self, module): ) ) - def _get_odoo_module_branch_id(self, module: str, branch: str) -> int: + def _get_odoo_module_branch_id(self, repo_id: int, module: str, branch: str) -> int: args = [ + ("repository_id", "=", repo_id), ("module_id", "=", module), ("branch_id", "=", branch), ] From d174da63cb7e9434c892af56ecd745a6c18e6dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Thu, 31 Oct 2024 09:05:28 +0100 Subject: [PATCH 20/50] odoo_repository_*: rename some filters --- odoo_repository_migration/views/odoo_module_branch.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/odoo_repository_migration/views/odoo_module_branch.xml b/odoo_repository_migration/views/odoo_module_branch.xml index d0558fc4..5ee36f58 100644 --- a/odoo_repository_migration/views/odoo_module_branch.xml +++ b/odoo_repository_migration/views/odoo_module_branch.xml @@ -27,7 +27,7 @@ odoo.module.branch - + Date: Wed, 13 Nov 2024 09:00:30 +0100 Subject: [PATCH 21/50] fixup! MigrationScanner: upgrade oca-port --- .../models/odoo_repository.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py index 411af9ff..4e100192 100644 --- a/odoo_repository_migration/models/odoo_repository.py +++ b/odoo_repository_migration/models/odoo_repository.py @@ -106,21 +106,23 @@ def _migration_create_jobs_scan_module(self, migration_path, modules_to_scan): ), identity_key=identity_exact, ) - job = delayable._scan_migration_module( - migration_path.id, module.module_id.name - ) + job = delayable._scan_migration_module(migration_path.id, module.id) jobs.append(job) return jobs - def _scan_migration_module(self, migration_path_id, module_name): - """Scan migration path for `module_name`.""" + def _scan_migration_module(self, migration_path_id, module_branch_id): + """Scan migration path for `module_branch_id`.""" + module = self.env["odoo.module.branch"].browse(module_branch_id).exists() + module.ensure_one() migration_path = ( self.env["odoo.migration.path"].browse(migration_path_id).exists() ) params = self._prepare_migration_scanner_parameters(migration_path) try: scanner = MigrationScannerOdooEnv(**params) - return scanner.scan(modules=[module_name]) + return scanner.scan( + addons_path=module.addons_path, module_names=[module.module_id.name] + ) except Exception as exc: raise RetryableJobError("Scanner error") from exc From d5747e56b8c1ba3f336bf2099afbde49d65273e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Tue, 19 Nov 2024 16:15:05 +0100 Subject: [PATCH 22/50] odoo_repository[_migration]: fix access to 'ir.config_parameter' --- odoo_repository_migration/models/odoo_repository.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py index 4e100192..065282d2 100644 --- a/odoo_repository_migration/models/odoo_repository.py +++ b/odoo_repository_migration/models/odoo_repository.py @@ -146,7 +146,7 @@ def _migration_get_modules_to_scan(self, migration_path): def _prepare_migration_scanner_parameters(self, migration_path): ir_config = self.env["ir.config_parameter"] - repositories_path = ir_config.get_param(self._repositories_path_key) + repositories_path = ir_config.sudo().get_param(self._repositories_path_key) mig_path = ( migration_path.source_branch_id.name, migration_path.target_branch_id.name, From 87d9b9a03fe3ccc80a9c1d28ec1dca154fecf797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Thu, 17 Oct 2024 14:34:28 +0200 Subject: [PATCH 23/50] odoo_repository_migration: auto-archive 'odoo.module.branch.migration' --- odoo_repository_migration/models/odoo_module_branch_migration.py | 1 + 1 file changed, 1 insertion(+) diff --git a/odoo_repository_migration/models/odoo_module_branch_migration.py b/odoo_repository_migration/models/odoo_module_branch_migration.py index b12e2c9a..88af9062 100644 --- a/odoo_repository_migration/models/odoo_module_branch_migration.py +++ b/odoo_repository_migration/models/odoo_module_branch_migration.py @@ -70,6 +70,7 @@ class OdooModuleBranchMigration(models.Model): results_text = fields.Text(compute="_compute_results_text") last_source_scanned_commit = fields.Char() last_target_scanned_commit = fields.Char() + active = fields.Boolean(related="migration_path_id.active", store=True) _sql_constraints = [ ( From 33edbb8f9a8a1371948e9457a8e7df9bacdd2ee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Thu, 17 Oct 2024 14:35:09 +0200 Subject: [PATCH 24/50] odoo_repository_migration: fix 'migration_scan' flag Remove migration path that doesn't match branches scanned in the repository (e.g. 18.0 branch could be missing in a repo while a migration path 16.0 -> 18.0 is configured, so no need to do a migration scan in this case). --- odoo_repository_migration/__manifest__.py | 2 +- .../migrations/16.0.1.0.1/post-migration.py | 22 +++++++++++++++++++ .../models/odoo_module_branch.py | 22 ++++++++++++++----- .../models/odoo_repository.py | 3 --- 4 files changed, 40 insertions(+), 9 deletions(-) create mode 100644 odoo_repository_migration/migrations/16.0.1.0.1/post-migration.py diff --git a/odoo_repository_migration/__manifest__.py b/odoo_repository_migration/__manifest__.py index 46cbf98a..f1d65302 100644 --- a/odoo_repository_migration/__manifest__.py +++ b/odoo_repository_migration/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Odoo Repository Migration Data", "summary": "Collect modules migration data for Odoo Repositories.", - "version": "16.0.1.0.0", + "version": "16.0.1.0.1", "category": "Tools", "author": "Camptocamp, Odoo Community Association (OCA)", "website": "https://github.com/camptocamp/odoo-repository", diff --git a/odoo_repository_migration/migrations/16.0.1.0.1/post-migration.py b/odoo_repository_migration/migrations/16.0.1.0.1/post-migration.py new file mode 100644 index 00000000..8262205f --- /dev/null +++ b/odoo_repository_migration/migrations/16.0.1.0.1/post-migration.py @@ -0,0 +1,22 @@ +# Copyright 2024 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +import logging + +from odoo import SUPERUSER_ID, api + +_logger = logging.getLogger(__name__) + + +def migrate(cr, version): + if not version: + return + env = api.Environment(cr, SUPERUSER_ID, {}) + recompute_migration_scan(env) + + +def recompute_migration_scan(env): + _logger.info("Recompute '.migration_scan' field...") + mods = env["odoo.module.branch"].search([]) + mods.modified(["last_scanned_commit"]) + mods.flush_recordset(["migration_scan"]) diff --git a/odoo_repository_migration/models/odoo_module_branch.py b/odoo_repository_migration/models/odoo_module_branch.py index a3e54a6a..c8ececda 100644 --- a/odoo_repository_migration/models/odoo_module_branch.py +++ b/odoo_repository_migration/models/odoo_module_branch.py @@ -20,11 +20,18 @@ class OdooModuleBranch(models.Model): ) @api.depends( + "removed", + "pr_url", "last_scanned_commit", "migration_ids.last_source_scanned_commit", + "repository_id.collect_migration_data", ) def _compute_migration_scan(self): for rec in self: + # Do not scan removed or pending (in PR) modules + if rec.removed or rec.pr_url: + rec.migration_scan = False + continue # Default repository migration scan policy rec.migration_scan = rec.repository_id.collect_migration_data if not rec.migration_scan: @@ -33,13 +40,18 @@ def _compute_migration_scan(self): if not rec.last_scanned_commit: continue # Migration scan to do as soon as a migration path is missing - # among existing scans + # among existing scans. However, we remove migration path that doesn't + # match branches scanned in the repository (e.g. 18.0 branch could + # be missing in a repo while a migration path 16.0 -> 18.0 is + # configured, so no need to do a migration scan in this case). + available_repo_branches = rec.repository_id.branch_ids.branch_id available_migration_paths = self.env["odoo.migration.path"].search( - [("source_branch_id", "=", rec.branch_id.id)] - ) - scanned_migration_paths = rec.migration_ids.migration_path_id.filtered( - "active" + [ + ("source_branch_id", "=", rec.branch_id.id), + ("target_branch_id", "in", available_repo_branches.ids), + ] ) + scanned_migration_paths = rec.migration_ids.migration_path_id if available_migration_paths != scanned_migration_paths: rec.migration_scan = True continue diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py index 065282d2..521100b6 100644 --- a/odoo_repository_migration/models/odoo_repository.py +++ b/odoo_repository_migration/models/odoo_repository.py @@ -138,9 +138,6 @@ def _migration_get_modules_to_scan(self, migration_path): ), ("branch_id", "=", migration_path.source_branch_id.id), ("migration_scan", "=", True), - # Do not scan removed or pending (in PR) modules - ("removed", "=", False), - ("last_scanned_commit", "!=", False), ] ) From 2a953cafd96b2a4ae4b10191d60902d7da36b23e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Thu, 17 Oct 2024 14:52:35 +0200 Subject: [PATCH 25/50] odoo_repository_migration: do not force scan when creating a migration path And change the method/button 'action_force_scan' to 'action_scan'. Thanks to the new way jobs are spawned (PR #53) and the new `.migration_scan` flag, there is no need to reset the last scanned commits to perform a migration scan on relevant modules, preserving a lot of computation time and resources. --- .../models/odoo_migration_path.py | 10 +++------- .../views/odoo_migration_path.xml | 6 +++--- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/odoo_repository_migration/models/odoo_migration_path.py b/odoo_repository_migration/models/odoo_migration_path.py index 605fc423..7dd314be 100644 --- a/odoo_repository_migration/models/odoo_migration_path.py +++ b/odoo_repository_migration/models/odoo_migration_path.py @@ -50,18 +50,14 @@ def create(self, vals_list): ) modules.modified(["last_scanned_commit"]) modules.flush_recordset(["migration_scan"]) - # Automatically launch a scan on all relevant repositories when a - # migration path is created - if not self.env.context.get("disable_force_scan"): - records.action_force_scan() return records - def action_force_scan(self): - """Force the scan of the source branch. + def action_scan(self): + """Scan the source+target branches. Scan is done on all related repositories configured to collect migration data. """ branches = self.source_branch_id | self.target_branch_id return branches.repository_branch_ids.filtered( lambda o: o.repository_id.collect_migration_data - ).action_force_scan() + ).action_scan() diff --git a/odoo_repository_migration/views/odoo_migration_path.xml b/odoo_repository_migration/views/odoo_migration_path.xml index 151c9c79..a2c5c716 100644 --- a/odoo_repository_migration/views/odoo_migration_path.xml +++ b/odoo_repository_migration/views/odoo_migration_path.xml @@ -10,11 +10,11 @@
From 4d12167a575a574f48f191ce30e9255d223fd46e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Tue, 19 Nov 2024 17:05:36 +0100 Subject: [PATCH 26/50] odoo_repository_migration: add tests on 'migration_scan' flag --- odoo_repository_migration/tests/__init__.py | 1 + .../tests/test_odoo_module_branch.py | 68 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 odoo_repository_migration/tests/__init__.py create mode 100644 odoo_repository_migration/tests/test_odoo_module_branch.py diff --git a/odoo_repository_migration/tests/__init__.py b/odoo_repository_migration/tests/__init__.py new file mode 100644 index 00000000..39bb08d7 --- /dev/null +++ b/odoo_repository_migration/tests/__init__.py @@ -0,0 +1 @@ +from . import test_odoo_module_branch diff --git a/odoo_repository_migration/tests/test_odoo_module_branch.py b/odoo_repository_migration/tests/test_odoo_module_branch.py new file mode 100644 index 00000000..0d7076b5 --- /dev/null +++ b/odoo_repository_migration/tests/test_odoo_module_branch.py @@ -0,0 +1,68 @@ +# Copyright 2024 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo.addons.odoo_repository.tests import common + + +class TestOdooModuleBranch(common.Common): + def setUp(self): + super().setUp() + self.module = self._create_odoo_module("my_module") + self.repo_branch = self._create_odoo_repository_branch( + self.odoo_repository, self.branch + ) + self.repo_branch2 = self._create_odoo_repository_branch( + self.odoo_repository, self.branch2 + ) + self.module_branch = self._create_odoo_module_branch( + self.module, + self.branch, + specific=False, + repository_branch_id=self.repo_branch.id, + last_scanned_commit="sha", + ) + + def test_migration_scan_removed(self): + self.module_branch.removed = True + self.assertFalse(self.module_branch.migration_scan) + + def test_migration_scan_pr_url(self): + self.module_branch.pr_url = "https://my/pr" + self.assertFalse(self.module_branch.migration_scan) + + def test_migration_scan_repo_collect_migration_data(self): + self.assertFalse(self.module_branch.migration_scan) + self.odoo_repository.collect_migration_data = True + # It's not enough to flag the module as there is no available + # migration path to scan + self.assertFalse(self.module_branch.migration_scan) + + def test_migration_scan_never_scanned(self): + self.module_branch.last_scanned_commit = False + self.assertFalse(self.module_branch.migration_scan) + self.odoo_repository.collect_migration_data = True + self.assertTrue(self.module_branch.migration_scan) + + def test_migration_scan_missing_migration_path(self): + self.odoo_repository.collect_migration_data = True + self.assertFalse(self.module_branch.migration_scan) + mig_path = self.env["odoo.migration.path"].create( + { + "source_branch_id": self.branch.id, + "target_branch_id": self.branch2.id, + } + ) + self.assertTrue(self.module_branch.migration_scan) + # Once we collected migration data for the expected branch+commit + # the module doesn't require a migration scan anymore + self.module_branch.migration_ids |= ( + # Simulate migration data addition + self.env["odoo.module.branch.migration"].create( + { + "module_branch_id": self.module_branch.id, + "migration_path_id": mig_path.id, + "last_source_scanned_commit": self.module_branch.last_scanned_commit, + } + ) + ) + self.assertFalse(self.module_branch.migration_scan) From 5ff0c5186ed174be27de5a618cc06f8f531f2f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Mon, 9 Dec 2024 10:02:13 +0100 Subject: [PATCH 27/50] odoo_repository_migration: fix migration data computation --- odoo_repository_migration/__manifest__.py | 2 +- .../migrations/16.0.1.1.0/post-migration.py | 26 ++++ .../models/odoo_module_branch.py | 39 ++++-- .../models/odoo_module_branch_migration.py | 59 ++++++++- .../tests/test_odoo_module_branch.py | 120 ++++++++++++++++-- odoo_repository_migration/utils/scanner.py | 13 +- .../views/odoo_module_branch.xml | 1 + .../views/odoo_module_branch_migration.xml | 3 + 8 files changed, 237 insertions(+), 26 deletions(-) create mode 100644 odoo_repository_migration/migrations/16.0.1.1.0/post-migration.py diff --git a/odoo_repository_migration/__manifest__.py b/odoo_repository_migration/__manifest__.py index f1d65302..f6f6d967 100644 --- a/odoo_repository_migration/__manifest__.py +++ b/odoo_repository_migration/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Odoo Repository Migration Data", "summary": "Collect modules migration data for Odoo Repositories.", - "version": "16.0.1.0.1", + "version": "16.0.1.1.0", "category": "Tools", "author": "Camptocamp, Odoo Community Association (OCA)", "website": "https://github.com/camptocamp/odoo-repository", diff --git a/odoo_repository_migration/migrations/16.0.1.1.0/post-migration.py b/odoo_repository_migration/migrations/16.0.1.1.0/post-migration.py new file mode 100644 index 00000000..7de23bfe --- /dev/null +++ b/odoo_repository_migration/migrations/16.0.1.1.0/post-migration.py @@ -0,0 +1,26 @@ +# Copyright 2024 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +import logging + +from odoo import SUPERUSER_ID, api + +_logger = logging.getLogger(__name__) + + +def migrate(cr, version): + if not version: + return + env = api.Environment(cr, SUPERUSER_ID, {}) + recompute_migration_scan(env) + + +def recompute_migration_scan(env): + _logger.info("Recompute '.migration_scan' field...") + mb_model = env["odoo.module.branch"] + mods = mb_model.search([]) + mods.modified(["last_scanned_commit"]) + mods.flush_recordset(["migration_scan"]) + # Reset last target scanned commit on those that need a migration scan + mods_to_scan = mb_model.search([("migration_scan", "=", True)]) + mods_to_scan.migration_ids.write({"last_target_scanned_commit": False}) diff --git a/odoo_repository_migration/models/odoo_module_branch.py b/odoo_repository_migration/models/odoo_module_branch.py index c8ececda..36dfce56 100644 --- a/odoo_repository_migration/models/odoo_module_branch.py +++ b/odoo_repository_migration/models/odoo_module_branch.py @@ -23,7 +23,7 @@ class OdooModuleBranch(models.Model): "removed", "pr_url", "last_scanned_commit", - "migration_ids.last_source_scanned_commit", + "migration_ids.migration_scan", "repository_id.collect_migration_data", ) def _compute_migration_scan(self): @@ -55,14 +55,8 @@ def _compute_migration_scan(self): if available_migration_paths != scanned_migration_paths: rec.migration_scan = True continue - # Migration scan to do if last scanned commit doesn't match the last - # migration scan - for migration in rec.migration_ids: - if migration.last_source_scanned_commit != rec.last_scanned_commit: - rec.migration_scan = True - break - # Reaching this point means no scan is required - rec.migration_scan = False + # Migration scan to do if any of the migration path requires one + rec.migration_scan = any(rec.migration_ids.mapped("migration_scan")) def _to_dict(self): # Add the migrations data @@ -71,3 +65,30 @@ def _to_dict(self): for migration in self.migration_ids: data["migrations"].append(migration._to_dict()) return data + + @api.model_create_multi + def create(self, vals_list): + recs = super().create(vals_list) + recs._update_migration_target_module_id() + return recs + + def write(self, vals): + res = super().write(vals) + # When 'pr_url' is set or unset, this means the module has been found + # in a PR or has been merged upstream. We want to recompute the target + # module in migration data in such case. + if "pr_url" in vals: + self._update_migration_target_module_id() + return res + + def _update_migration_target_module_id(self): + """Update `target_module_id` field on relevant module migration records.""" + for rec in self: + migrations = self.env["odoo.module.branch.migration"].search( + [ + ("module_id", "=", rec.module_id.id), + ("target_branch_id", "=", rec.branch_id.id), + ] + ) + # Recompute 'target_module_id' field + migrations._compute_target_module_branch_id() diff --git a/odoo_repository_migration/models/odoo_module_branch_migration.py b/odoo_repository_migration/models/odoo_module_branch_migration.py index 88af9062..b678a04d 100644 --- a/odoo_repository_migration/models/odoo_module_branch_migration.py +++ b/odoo_repository_migration/models/odoo_module_branch_migration.py @@ -15,7 +15,7 @@ class OdooModuleBranchMigration(models.Model): module_branch_id = fields.Many2one( comodel_name="odoo.module.branch", ondelete="cascade", - string="Module", + string="Source", required=True, index=True, ) @@ -46,6 +46,14 @@ class OdooModuleBranchMigration(models.Model): store=True, index=True, ) + target_module_branch_id = fields.Many2one( + comodel_name="odoo.module.branch", + ondelete="cascade", + string="Target", + compute="_compute_target_module_branch_id", + store=True, + index=True, + ) author_ids = fields.Many2many(related="module_branch_id.author_ids") maintainer_ids = fields.Many2many(related="module_branch_id.maintainer_ids") process = fields.Char(index=True) @@ -71,6 +79,11 @@ class OdooModuleBranchMigration(models.Model): last_source_scanned_commit = fields.Char() last_target_scanned_commit = fields.Char() active = fields.Boolean(related="migration_path_id.active", store=True) + migration_scan = fields.Boolean( + compute="_compute_migration_scan", + store=True, + help="Technical field telling if this migration path needs a migration scan.", + ) _sql_constraints = [ ( @@ -92,6 +105,17 @@ def _compute_display_name(self): f"{rec.source_branch_id.name} -> {rec.target_branch_id.name}" ) + @api.depends("module_branch_id", "migration_path_id") + def _compute_target_module_branch_id(self): + module_branch_model = self.env["odoo.module.branch"] + for rec in self: + rec.target_module_branch_id = module_branch_model._find( + rec.migration_path_id.target_branch_id, + rec.module_branch_id.module_id, + rec.module_branch_id.repository_id, + domain=[("installable", "=", True)], + ) + @api.depends("process", "pr_url") def _compute_state(self): for rec in self: @@ -109,6 +133,32 @@ def _compute_results_text(self): for rec in self: rec.results_text = pprint.pformat(rec.results) + @api.depends( + "last_source_scanned_commit", + "last_target_scanned_commit", + "pr_url", + "target_module_branch_id.pr_url", + "target_module_branch_id.last_scanned_commit", + ) + def _compute_migration_scan(self): + # Migration scan to do if last scanned commit doesn't match the last + # migration scan, both for source and target modules. + for rec in self: + rec.migration_scan = False + if ( + rec.last_source_scanned_commit + != rec.module_branch_id.last_scanned_commit + ): + rec.migration_scan = True + elif ( + rec.target_module_branch_id.last_scanned_commit + and rec.last_target_scanned_commit + != rec.target_module_branch_id.last_scanned_commit + ): + rec.migration_scan = True + elif rec.target_module_branch_id.pr_url != rec.pr_url: + rec.migration_scan = True + @api.model @api.returns("odoo.module.branch.migration") def push_scanned_data(self, module_branch_id, data): @@ -124,9 +174,10 @@ def push_scanned_data(self, module_branch_id, data): "last_source_scanned_commit": data["source_commit"], "last_target_scanned_commit": data["target_commit"], } - for key in ("process", "results"): - if key in data: - values[key] = data[key] + # Update migration data only if a migration scan occured + if "report" in data: + values["process"] = data["report"].get("process", False) + values["results"] = data["report"].get("results", {}) return self._create_or_update(module_branch_id, migration_path, values) def _create_or_update(self, module_branch_id, migration_path, values): diff --git a/odoo_repository_migration/tests/test_odoo_module_branch.py b/odoo_repository_migration/tests/test_odoo_module_branch.py index 0d7076b5..ebfa7254 100644 --- a/odoo_repository_migration/tests/test_odoo_module_branch.py +++ b/odoo_repository_migration/tests/test_odoo_module_branch.py @@ -22,6 +22,22 @@ def setUp(self): last_scanned_commit="sha", ) + def _simulate_migration_scan(self, target_commit, report=None): + """Helper method that pushes scanned migration data.""" + data = { + "module": self.module_branch.module_name, + "source_branch": self.branch.name, + "target_branch": self.branch2.name, + "source_commit": self.module_branch.last_scanned_commit, + "target_commit": target_commit, + } + if report is not None: + data["report"] = report + return self.env["odoo.module.branch.migration"].push_scanned_data( + self.module_branch.id, + data, + ) + def test_migration_scan_removed(self): self.module_branch.removed = True self.assertFalse(self.module_branch.migration_scan) @@ -39,30 +55,114 @@ def test_migration_scan_repo_collect_migration_data(self): def test_migration_scan_never_scanned(self): self.module_branch.last_scanned_commit = False + self.assertFalse(self.module_branch.migration_ids) self.assertFalse(self.module_branch.migration_scan) self.odoo_repository.collect_migration_data = True + self.assertFalse(self.module_branch.migration_ids) self.assertTrue(self.module_branch.migration_scan) def test_migration_scan_missing_migration_path(self): self.odoo_repository.collect_migration_data = True + self.assertFalse(self.module_branch.migration_ids) self.assertFalse(self.module_branch.migration_scan) - mig_path = self.env["odoo.migration.path"].create( + self.env["odoo.migration.path"].create( { "source_branch_id": self.branch.id, "target_branch_id": self.branch2.id, } ) + self.assertFalse(self.module_branch.migration_ids) self.assertTrue(self.module_branch.migration_scan) # Once we collected migration data for the expected branch+commit # the module doesn't require a migration scan anymore - self.module_branch.migration_ids |= ( - # Simulate migration data addition - self.env["odoo.module.branch.migration"].create( - { - "module_branch_id": self.module_branch.id, - "migration_path_id": mig_path.id, - "last_source_scanned_commit": self.module_branch.last_scanned_commit, - } - ) + self._simulate_migration_scan( + "target_commit1", report={"process": "migrate", "results": {}} ) + self.assertTrue(self.module_branch.migration_ids) + self.assertFalse(self.module_branch.migration_scan) + + def test_migration_scan_target_module_in_review_then_merged(self): + """Test full flow of the migration of a module. + + 1) At first, the module of the source branch needs a migration scan + because the migration data are missing for the target branch. + 2) Once the migration is done (and migration data available), the migration + scan is not needed anymore. + 3) Then the target module could be found in a PR to review, but this + doesn't + """ + self.odoo_repository.collect_migration_data = True + # Simulate a scan of a given migration path while the target module is + # not yet migrated/available in a repository + self.assertFalse(self.module_branch.migration_ids) + self.assertFalse(self.module_branch.migration_scan) + self.env["odoo.migration.path"].create( + { + "source_branch_id": self.branch.id, + "target_branch_id": self.branch2.id, + } + ) + self.assertFalse(self.module_branch.migration_ids) + self.assertTrue(self.module_branch.migration_scan) + self._simulate_migration_scan( + "target_commit1", report={"process": "migrate", "results": {}} + ) + self.assertTrue(self.module_branch.migration_ids) + self.assertFalse(self.module_branch.migration_ids.migration_scan) + self.assertFalse(self.module_branch.migration_scan) + self.assertEqual(self.module_branch.migration_ids.state, "migrate") + # Make the module available for targeted branch in review (available in a PR). + # The source module now needs a migration scan as the target module is + # available in a PR, the migration status has to be updated. + target_module_branch = self._create_odoo_module_branch( + self.module, + self.branch2, + specific=False, + repository_branch_id=self.repo_branch.id, + # Module available in a PR + pr_url="https://my/pr", + ) + self.assertEqual( + self.module_branch.migration_ids.target_module_branch_id, + target_module_branch, + ) + self.assertEqual(self.module_branch.migration_ids.state, "migrate") + self.assertTrue(self.module_branch.migration_ids.migration_scan) + self.assertTrue(self.module_branch.migration_scan) + # Simulate the migration scan. + # The source module doesn't need a migration scan anymore. + self._simulate_migration_scan( + "target_commit1", + report={ + "process": "migrate", + "results": {"existing_pr": {"url": target_module_branch.pr_url}}, + }, + ) + self.assertEqual(self.module_branch.migration_ids.state, "review_migration") + self.assertFalse(self.module_branch.migration_ids.migration_scan) + self.assertFalse(self.module_branch.migration_scan) + # Merge the module in the upstream repository. + # The source module now needs a migration scan (to check if there is + # something to port, or to set the module as fully ported...). + target_module_branch.write( + { + "last_scanned_commit": "target_commit2", + # When 'pr_url' is unset, this means the module has been merged + "pr_url": False, + } + ) + self.module_branch.migration_ids.last_target_scanned_commit = ( + target_module_branch.last_scanned_commit + ) + self.assertEqual( + self.module_branch.migration_ids.target_module_branch_id, + target_module_branch, + ) + self.assertTrue(self.module_branch.migration_ids.migration_scan) + self.assertTrue(self.module_branch.migration_scan) + # Simulate the migration scan. + # The source module is fully ported and doesn't need a migration scan afterwards. + self._simulate_migration_scan("target_commit2", report={"results": {}}) + self.assertEqual(self.module_branch.migration_ids.state, "fully_ported") + self.assertFalse(self.module_branch.migration_ids.migration_scan) self.assertFalse(self.module_branch.migration_scan) diff --git a/odoo_repository_migration/utils/scanner.py b/odoo_repository_migration/utils/scanner.py index 994add61..c4f3eb81 100644 --- a/odoo_repository_migration/utils/scanner.py +++ b/odoo_repository_migration/utils/scanner.py @@ -70,16 +70,25 @@ def _get_odoo_module_branch_migration_id( return migration.id def _get_odoo_module_branch_migration_data( - self, module: str, source_branch: str, target_branch: str + self, repo_id: int, module: str, source_branch: str, target_branch: str ) -> dict: args = [ + ("module_branch_id.repository_id", "=", repo_id), ("module_id", "=", module), ("source_branch_id", "=", source_branch), ("target_branch_id", "=", target_branch), ] migration = self.env["odoo.module.branch.migration"].search(args) if migration: - return migration.read()[0] + data = { + "last_source_scanned_commit": migration.module_branch_id.last_scanned_commit, + "last_target_scanned_commit": ( + migration.target_module_branch_id.last_scanned_commit + ), + "last_source_mig_scanned_commit": migration.last_source_scanned_commit, + "last_target_mig_scanned_commit": migration.last_target_scanned_commit, + } + return data return {} def _push_scanned_data(self, module_branch_id: int, data: dict): diff --git a/odoo_repository_migration/views/odoo_module_branch.xml b/odoo_repository_migration/views/odoo_module_branch.xml index 5ee36f58..a0cd9738 100644 --- a/odoo_repository_migration/views/odoo_module_branch.xml +++ b/odoo_repository_migration/views/odoo_module_branch.xml @@ -15,6 +15,7 @@ + diff --git a/odoo_repository_migration/views/odoo_module_branch_migration.xml b/odoo_repository_migration/views/odoo_module_branch_migration.xml index cad1e2ae..7872c8d3 100644 --- a/odoo_repository_migration/views/odoo_module_branch_migration.xml +++ b/odoo_repository_migration/views/odoo_module_branch_migration.xml @@ -14,6 +14,7 @@ + @@ -36,8 +37,10 @@ + + From af97fff667c0f4a60d1f2854e0f27b99ecaf9a20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Fri, 10 Jan 2025 16:12:08 +0100 Subject: [PATCH 28/50] odoo_project_migration: handle projects in migration data E.g this allows to cross modules common to different projects, to share the costs between them regarding a migration. --- odoo_repository_migration/views/odoo_module_branch_migration.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/odoo_repository_migration/views/odoo_module_branch_migration.xml b/odoo_repository_migration/views/odoo_module_branch_migration.xml index 7872c8d3..d14ed39b 100644 --- a/odoo_repository_migration/views/odoo_module_branch_migration.xml +++ b/odoo_repository_migration/views/odoo_module_branch_migration.xml @@ -19,6 +19,7 @@ + From cd2105666d685e49a15ceb8d1021d5a0b600661a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Fri, 28 Feb 2025 11:20:26 +0100 Subject: [PATCH 29/50] odoo_repository_migration: hide columns by default in 'Migrations' menu --- .../views/odoo_module_branch_migration.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/odoo_repository_migration/views/odoo_module_branch_migration.xml b/odoo_repository_migration/views/odoo_module_branch_migration.xml index d14ed39b..17eb9973 100644 --- a/odoo_repository_migration/views/odoo_module_branch_migration.xml +++ b/odoo_repository_migration/views/odoo_module_branch_migration.xml @@ -37,9 +37,9 @@ - - - + + + From 4a8be22a3ad21ebe5701389aba7159ef60624dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Thu, 13 Mar 2025 16:52:53 +0100 Subject: [PATCH 30/50] odoo_repository_migration: support migration scan between two repositories This supports the migration scan for modules that have been moved to another repository. This commit also adds new technical flags and migration states to improve module qualification during a migration: - Moved to standard - Moved to OCA - Moved to generic repo (specific modules moved to generic repo) Migration with such states won't trigger a migration scan as modules could be different. E.g. 'l10n_eu_oss' Odoo module is not the same than OCA one starting from 15.0, and OCA renamed its module 'l10n_eu_oss_oca' from this version, either to complete std implementation, or to propose another one. So these states will help integrators to identify such modules. Later we could add a feature to set a given module as renamed from a given version, like 'l10n_eu_oss' renamed to 'l10n_eu_oss_oca', so the module won't be qualified with 'Moved to standard' state as it's just a renaming. But such feature will require to also improve 'oca-port' to handle such case to perform a migration scan. --- odoo_repository_migration/__manifest__.py | 2 +- .../migrations/16.0.1.2.0/post-migration.py | 56 ++++++++ .../models/odoo_module_branch_migration.py | 90 ++++++++++++- .../models/odoo_repository.py | 30 ++++- .../tests/test_odoo_module_branch.py | 122 ++++++++++++++++++ 5 files changed, 295 insertions(+), 5 deletions(-) create mode 100644 odoo_repository_migration/migrations/16.0.1.2.0/post-migration.py diff --git a/odoo_repository_migration/__manifest__.py b/odoo_repository_migration/__manifest__.py index f6f6d967..9625b7aa 100644 --- a/odoo_repository_migration/__manifest__.py +++ b/odoo_repository_migration/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Odoo Repository Migration Data", "summary": "Collect modules migration data for Odoo Repositories.", - "version": "16.0.1.1.0", + "version": "16.0.1.2.0", "category": "Tools", "author": "Camptocamp, Odoo Community Association (OCA)", "website": "https://github.com/camptocamp/odoo-repository", diff --git a/odoo_repository_migration/migrations/16.0.1.2.0/post-migration.py b/odoo_repository_migration/migrations/16.0.1.2.0/post-migration.py new file mode 100644 index 00000000..471bdb3e --- /dev/null +++ b/odoo_repository_migration/migrations/16.0.1.2.0/post-migration.py @@ -0,0 +1,56 @@ +# Copyright 2024 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +import logging + +from odoo import SUPERUSER_ID, api + +_logger = logging.getLogger(__name__) + + +def migrate(cr, version): + if not version: + return + env = api.Environment(cr, SUPERUSER_ID, {}) + fix_migration_states(env) + + +def fix_migration_states(env): + _logger.info("Plan a scan to fix '.state' field...") + query = """ + SELECT mig.id + FROM odoo_module_branch_migration mig + JOIN odoo_module_branch AS source + ON mig.module_branch_id=source.id + JOIN odoo_module_branch AS target + ON mig.target_module_branch_id=target.id + WHERE source.repository_branch_id IS NOT NULL + AND target.repository_branch_id IS NOT NULL + AND source.repository_id != target.repository_id; + """ + env.cr.execute(query) + mig_ids = [row[0] for row in env.cr.fetchall()] + # Reset 'last_target_scanned_commit' to recompute 'migration_scan' + if mig_ids: + query = """ + UPDATE odoo_module_branch_migration + SET last_target_scanned_commit=NULL + WHERE id IN %s; + """ + args = (tuple(mig_ids),) + env.cr.execute(query, args) + # Reset collected migration data on modules that shouldn't have any + mbm_model = env["odoo.module.branch.migration"] + migs = mbm_model.search( + [ + ("results", "!=", False), + ("repository_id.collect_migration_data", "=", False), + ] + ) + migs.results = False + # Recompute migration state/flag, especially for modules moved to another repo + # that won't trigger a migration scan. + migs = mbm_model.search([("id", "in", mig_ids)]) + env.add_to_compute(migs._fields["state"], migs) + env.add_to_compute(migs._fields["migration_scan"], migs) + migs.modified(["state", "migration_scan"]) diff --git a/odoo_repository_migration/models/odoo_module_branch_migration.py b/odoo_repository_migration/models/odoo_module_branch_migration.py index b678a04d..aea3d234 100644 --- a/odoo_repository_migration/models/odoo_module_branch_migration.py +++ b/odoo_repository_migration/models/odoo_module_branch_migration.py @@ -57,12 +57,43 @@ class OdooModuleBranchMigration(models.Model): author_ids = fields.Many2many(related="module_branch_id.author_ids") maintainer_ids = fields.Many2many(related="module_branch_id.maintainer_ids") process = fields.Char(index=True) + moved_to_standard = fields.Boolean( + compute="_compute_moved_to_standard", + store=True, + help=( + "Module now available in Odoo standard code. " + "This module is maybe not exactly the same, and doesn't have the " + "same scope so it deserves a check during a migration." + ), + ) + moved_to_oca = fields.Boolean( + compute="_compute_moved_to_oca", + store=True, + help=( + "Module now available in OCA. " + "This module is maybe not exactly the same, and doesn't have the " + "same scope so it deserves a check during a migration." + ), + ) + moved_to_generic = fields.Boolean( + compute="_compute_moved_to_generic", + store=True, + string="Now generic", + help=( + "Specific module now available in a generic repository. " + "This module is maybe not exactly the same, and doesn't have the " + "same scope so it deserves a check during a migration." + ), + ) state = fields.Selection( selection=[ ("fully_ported", "Fully Ported"), ("migrate", "To migrate"), ("port_commits", "Commits to port"), ("review_migration", "Migration to review"), + ("moved_to_standard", "Moved to standard"), + ("moved_to_oca", "Moved to OCA"), + ("moved_to_generic", "Moved to generic repo"), ], string="Migration Status", compute="_compute_state", @@ -116,9 +147,58 @@ def _compute_target_module_branch_id(self): domain=[("installable", "=", True)], ) - @api.depends("process", "pr_url") + @api.depends("module_branch_id.is_standard", "target_module_branch_id.is_standard") + def _compute_moved_to_standard(self): + for rec in self: + rec.moved_to_standard = ( + not rec.module_branch_id.is_standard + and rec.target_module_branch_id.is_standard + ) + + @api.depends("org_id", "target_module_branch_id.org_id") + def _compute_moved_to_oca(self): + org_oca = self.env.ref( + "odoo_repository.odoo_repository_org_oca", raise_if_not_found=False + ) + for rec in self: + rec.moved_to_oca = False + if not org_oca: + continue + rec.moved_to_oca = ( + rec.org_id != org_oca and rec.target_module_branch_id.org_id == org_oca + ) + + @api.depends( + "repository_id.specific", "target_module_branch_id.repository_id.specific" + ) + def _compute_moved_to_generic(self): + for rec in self: + rec.moved_to_generic = ( + rec.repository_id.specific + and rec.target_module_branch_id.repository_id + and not rec.target_module_branch_id.repository_id.specific + ) + + @api.depends( + "process", "pr_url", "moved_to_standard", "moved_to_oca", "moved_to_generic" + ) def _compute_state(self): for rec in self: + if rec.moved_to_standard: + # Module moved to a standard repository (likely from OCA to + # odoo/odoo, like 'l10n_eu_oss', 'knowledge', ...). + # E.g. this could tell integrators that a module like + # 'l10n_eu_oss_oca' should now be used instead. + rec.state = "moved_to_standard" + continue + if rec.moved_to_oca: + # Module moved to an OCA repository + rec.state = "moved_to_oca" + continue + if rec.moved_to_generic: + # Specific module moved to a generic repository (public or private) + rec.state = "moved_to_generic" + continue rec.state = rec.process or "fully_ported" if rec.process == "migrate" and rec.pr_url: rec.state = "review_migration" @@ -134,17 +214,25 @@ def _compute_results_text(self): rec.results_text = pprint.pformat(rec.results) @api.depends( + "repository_id.collect_migration_data", "last_source_scanned_commit", "last_target_scanned_commit", "pr_url", "target_module_branch_id.pr_url", "target_module_branch_id.last_scanned_commit", + "state", ) def _compute_migration_scan(self): # Migration scan to do if last scanned commit doesn't match the last # migration scan, both for source and target modules. for rec in self: rec.migration_scan = False + # No migration scan if repository is not configured to do it + if not rec.repository_id.collect_migration_data: + continue + # No migration scan for modules moved to Odoo/OCA/generic repo + if rec.state and rec.state.startswith("moved_to"): + continue if ( rec.last_source_scanned_commit != rec.module_branch_id.last_scanned_commit diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py index 521100b6..b2879e2a 100644 --- a/odoo_repository_migration/models/odoo_repository.py +++ b/odoo_repository_migration/models/odoo_repository.py @@ -117,7 +117,25 @@ def _scan_migration_module(self, migration_path_id, module_branch_id): migration_path = ( self.env["odoo.migration.path"].browse(migration_path_id).exists() ) - params = self._prepare_migration_scanner_parameters(migration_path) + # Check if module has already been migrated on target version but in a + # different repository. If so, tune the scanner parameters to perform + # the scan from current repo to new one. + target_repository = None + mig = module.migration_ids.filtered( + lambda mig: mig.migration_path_id.id == migration_path_id + ) + target_module = mig.target_module_branch_id + if target_module.repository_branch_id: + target_repository = target_module.repository_id + if not target_repository.collect_migration_data: + return ( + "Cannot collect migration data on repository " + f"{target_repository.display_name}." + ) + params = self._prepare_migration_scanner_parameters( + migration_path, target_repository + ) + # Run the migration scan try: scanner = MigrationScannerOdooEnv(**params) return scanner.scan( @@ -141,14 +159,16 @@ def _migration_get_modules_to_scan(self, migration_path): ] ) - def _prepare_migration_scanner_parameters(self, migration_path): + def _prepare_migration_scanner_parameters( + self, migration_path, target_repository=None + ): ir_config = self.env["ir.config_parameter"] repositories_path = ir_config.sudo().get_param(self._repositories_path_key) mig_path = ( migration_path.source_branch_id.name, migration_path.target_branch_id.name, ) - return { + params = { "org": self.org_id.name, "name": self.name, "clone_url": self.clone_url, @@ -163,6 +183,10 @@ def _prepare_migration_scanner_parameters(self, migration_path): "clone_name": self.clone_name, "env": self.env, } + if target_repository and target_repository != self: + params["new_repo_name"] = target_repository.name + params["new_repo_url"] = target_repository.clone_url + return params def _pre_create_or_update_module_branch(self, rec, values, raw_data): # Handle migration data diff --git a/odoo_repository_migration/tests/test_odoo_module_branch.py b/odoo_repository_migration/tests/test_odoo_module_branch.py index ebfa7254..6efabeab 100644 --- a/odoo_repository_migration/tests/test_odoo_module_branch.py +++ b/odoo_repository_migration/tests/test_odoo_module_branch.py @@ -21,6 +21,18 @@ def setUp(self): repository_branch_id=self.repo_branch.id, last_scanned_commit="sha", ) + self.std_repository = self.env.ref("odoo_repository.odoo_repository_odoo_odoo") + self.oca_repository = self.env.ref("odoo_repository.repo_oca_server_tools") + self.gen_repository = self.env["odoo.repository"].create( + { + "name": "new_repo", + "org_id": self.odoo_repository.org_id.id, + "repo_url": "http://example.net/new_repo", + "specific": False, + "to_scan": False, + } + ) + self.gen_repository.addons_path_ids = self.odoo_repository.addons_path_ids def _simulate_migration_scan(self, target_commit, report=None): """Helper method that pushes scanned migration data.""" @@ -166,3 +178,113 @@ def test_migration_scan_target_module_in_review_then_merged(self): self.assertEqual(self.module_branch.migration_ids.state, "fully_ported") self.assertFalse(self.module_branch.migration_ids.migration_scan) self.assertFalse(self.module_branch.migration_scan) + + def test_migration_scan_target_module_moved_to_standard(self): + """Module moved into a standard repository.""" + # Simulate a scan of a given migration path while the target module is + # not yet migrated/available in a repository + self.env["odoo.migration.path"].create( + { + "source_branch_id": self.branch.id, + "target_branch_id": self.branch2.id, + } + ) + self._simulate_migration_scan( + "target_commit1", report={"process": "migrate", "results": {}} + ) + self.assertTrue(self.module_branch.migration_ids) + mig = self.module_branch.migration_ids + self.assertFalse(mig.target_module_branch_id) + self.assertFalse(mig.migration_scan) + self.assertFalse(self.module_branch.migration_scan) + self.assertEqual(mig.state, "migrate") + # Then the module is discovered in a std repository + std_repo_branch = self._create_odoo_repository_branch( + self.std_repository, self.branch2 + ) + target_module_branch = self._create_odoo_module_branch( + self.module, + self.branch2, + specific=False, + is_standard=True, + repository_branch_id=std_repo_branch.id, + ) + self.assertEqual(mig.target_module_branch_id, target_module_branch) + self.assertTrue(mig.moved_to_standard) + self.assertFalse(mig.moved_to_oca) + self.assertFalse(mig.moved_to_generic) + self.assertEqual(mig.state, "moved_to_standard") + self.assertFalse(mig.migration_scan) + + def test_migration_scan_target_module_moved_to_oca(self): + """Module moved into an OCA repository.""" + # Simulate a scan of a given migration path while the target module is + # not yet migrated/available in a repository + self.env["odoo.migration.path"].create( + { + "source_branch_id": self.branch.id, + "target_branch_id": self.branch2.id, + } + ) + self._simulate_migration_scan( + "target_commit1", report={"process": "migrate", "results": {}} + ) + self.assertTrue(self.module_branch.migration_ids) + mig = self.module_branch.migration_ids + self.assertFalse(mig.target_module_branch_id) + self.assertFalse(mig.migration_scan) + self.assertFalse(self.module_branch.migration_scan) + self.assertEqual(mig.state, "migrate") + # Then the module is discovered in an OCA repository + oca_repo_branch = self._create_odoo_repository_branch( + self.oca_repository, self.branch2 + ) + target_module_branch = self._create_odoo_module_branch( + self.module, + self.branch2, + specific=False, + repository_branch_id=oca_repo_branch.id, + ) + self.assertEqual(mig.target_module_branch_id, target_module_branch) + self.assertFalse(mig.moved_to_standard) + self.assertTrue(mig.moved_to_oca) + self.assertFalse(mig.moved_to_generic) + self.assertEqual(mig.state, "moved_to_oca") + self.assertFalse(mig.migration_scan) + + def test_migration_scan_target_module_moved_to_generic(self): + """Specific module moved into a generic repository (that is not std or OCA).""" + self.odoo_repository.specific = True + # Simulate a scan of a given migration path while the target module is + # not yet migrated/available in a repository + self.env["odoo.migration.path"].create( + { + "source_branch_id": self.branch.id, + "target_branch_id": self.branch2.id, + } + ) + self._simulate_migration_scan( + "target_commit1", report={"process": "migrate", "results": {}} + ) + self.assertTrue(self.module_branch.migration_ids) + mig = self.module_branch.migration_ids + self.assertFalse(mig.target_module_branch_id) + self.assertFalse(mig.migration_scan) + self.assertFalse(self.module_branch.migration_scan) + self.assertEqual(mig.state, "migrate") + # Then the module is discovered in an OCA repository + gen_repo_branch = self._create_odoo_repository_branch( + self.gen_repository, self.branch2 + ) + target_module_branch = self._create_odoo_module_branch( + self.module, + self.branch2, + specific=False, + repository_branch_id=gen_repo_branch.id, + ) + self.assertEqual(mig.target_module_branch_id, target_module_branch) + self.assertFalse(mig.moved_to_standard) + self.assertFalse(mig.moved_to_oca) + self.assertTrue(mig.moved_to_generic) + self.assertEqual(mig.state, "moved_to_generic") + self.assertFalse(mig.migration_scan) From 54eac9e883a608751165cac2f22fadcd5d7c765c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Fri, 11 Apr 2025 15:32:02 +0200 Subject: [PATCH 31/50] odoo_repository_migration: able to qualify a module as renamed or replaced for next Odoo version Adapt odoo_project_migration accordingly, and show this info in CSV migration report. --- .../models/odoo_module_branch.py | 176 +++++++++++++++++- .../models/odoo_module_branch_migration.py | 78 +++++++- .../models/odoo_repository.py | 29 ++- .../tests/test_odoo_module_branch.py | 100 ++++++++++ .../views/odoo_module_branch.xml | 37 ++++ .../views/odoo_module_branch_migration.xml | 24 ++- 6 files changed, 427 insertions(+), 17 deletions(-) diff --git a/odoo_repository_migration/models/odoo_module_branch.py b/odoo_repository_migration/models/odoo_module_branch.py index 36dfce56..a33a66c3 100644 --- a/odoo_repository_migration/models/odoo_module_branch.py +++ b/odoo_repository_migration/models/odoo_module_branch.py @@ -1,24 +1,188 @@ # Copyright 2023 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) -from odoo import api, fields, models +from odoo import _, api, fields, models class OdooModuleBranch(models.Model): _inherit = "odoo.module.branch" + next_odoo_version_id = fields.Many2one( + comodel_name="odoo.branch", + compute="_compute_next_odoo_version_id", + ) + next_odoo_version_state = fields.Selection( + selection=[ + ("same", "is named the same"), + ("renamed", "has been renamed to"), + ("replaced", "has been replaced by"), + ], + inverse="_inverse_next_odoo_version_fields", + default="same", + required=True, + index=True, + ) + next_odoo_version_module_id = fields.Many2one( + comodel_name="odoo.module", + ondelete="restrict", + inverse="_inverse_next_odoo_version_fields", + string="Next Odoo Version Module", + index=True, + ) + next_odoo_version_module_branch_id = fields.Many2one( + comodel_name="odoo.module.branch", + compute="_compute_next_odoo_version_module_branch_id", + string="Next Odoo Version Module Branch", + ) migration_ids = fields.One2many( comodel_name="odoo.module.branch.migration", inverse_name="module_branch_id", string="Migrations", ) - migration_scan = fields.Boolean( compute="_compute_migration_scan", store=True, help="Technical field telling if this module is elligible for a migration scan.", ) + @api.depends("branch_id") + def _compute_next_odoo_version_id(self): + for rec in self: + next_odoo_version = False + if rec.branch_id: + next_odoo_version = self.env["odoo.branch"].search( + [ + ("odoo_version", "=", True), + ("sequence", ">", rec.branch_id.sequence), + ], + limit=1, + ) + rec.next_odoo_version_id = next_odoo_version + + @api.depends("next_odoo_version_id", "next_odoo_version_module_id") + def _compute_next_odoo_version_module_branch_id(self): + for rec in self: + rec.next_odoo_version_module_branch_id = False + # Stop there if no next version + if not rec.next_odoo_version_id: + continue + # Look for the next available version for this module name + rec.next_odoo_version_module_branch_id = self.search( + [ + ("branch_id", "=", rec.next_odoo_version_id.id), + ("module_id", "=", rec.module_id.id), + ], + limit=1, + ) + # Stop there if no renaming/relacement + if not rec.next_odoo_version_module_id: + continue + rec.next_odoo_version_module_branch_id = self.search( + [ + ("branch_id", "=", rec.next_odoo_version_id.id), + ("module_id", "=", rec.next_odoo_version_module_id.id), + ], + limit=1, + ) + + def _inverse_next_odoo_version_fields(self): + # Reset selected module if the module name doesn't change with next version + if self.next_odoo_version_state == "same": + self.next_odoo_version_module_id = False + # If module is renamed or replaced in next Odoo version, we reset the + # last target scan commits on all impacted migration paths. + # E.g. + # if a module on 17.0 is set as renamed starting from 18.0, + # all migration paths of this module targetting versions >= 18.0 + # should re-trigger a migration scan. + else: + migrations = ( + self.env["odoo.module.branch.migration"] + .search( + [ + ("module_id", "=", self.module_id.id), + ( + "target_branch_id.sequence", + ">=", + self.next_odoo_version_id.sequence, + ), + ] + ) + .sudo() + ) + migrations.last_target_scanned_commit = False + migrations._compute_renamed_to_module_id() + migrations._compute_replaced_by_module_id() + migrations._compute_state() + + def _replaced_by_module_in_target_version(self, target_branch): + """Return the module replacing current one in last module versions. + + Look for current + next modules as the migration scan could do a jump + 14.0 -> 18.0, while a module has been replaced starting from 18.0 (and + therefore flagged as replaced in 17.0 module data). + + We give the priority to last modules while checking them. + """ + self.ensure_one() + modules = self._get_next_versions(target_branch) + for module in modules.sorted( + key=lambda mod: mod.branch_id.sequence, reverse=True + ): + if module.next_odoo_version_state == "replaced": + return module.next_odoo_version_module_id + return self.env["odoo.module"] + + def _renamed_to_module_in_target_version(self, target_branch): + """Return the new module technical name in last module versions. + + Look for current + next modules as the migration scan could do a jump + 14.0 -> 18.0, while a module has been renamed starting from 18.0 (and + therefore flagged as renamed in 17.0 module data). + + We give the priority to last modules while checking them. + """ + self.ensure_one() + modules = self._get_next_versions(target_branch) + for module in modules.sorted( + key=lambda mod: mod.branch_id.sequence, reverse=True + ): + if module.next_odoo_version_state == "renamed": + return module.next_odoo_version_module_id + return self.env["odoo.module"] + + def _get_next_versions(self, target_branch): + self.ensure_one() + return self.env["odoo.module.branch"].search( + [ + ("module_id", "=", self.module_id.id), + ("branch_id.sequence", ">=", self.branch_id.sequence), + ("branch_id.sequence", "<", target_branch.sequence), + ] + ) + + def _get_next_module_branches(self, target_branch=None): + """Return all modules in the right version order starting from current one. + + This is taking into account module renamed or replaced in intermediate versions. + """ + if not self: + return self.browse() + self.ensure_one() + if target_branch: + assert self.branch_id.sequence < target_branch.sequence + next_module_branch = self.next_odoo_version_module_branch_id + next_module_branch_ids = [] + while next_module_branch: + if ( + target_branch + and next_module_branch.branch_id.sequence > target_branch.sequence + ): + break + next_module_branch_ids.append(next_module_branch.id) + next_module_branch = next_module_branch.next_odoo_version_module_branch_id + return self.browse(next_module_branch_ids) + @api.depends( "removed", "pr_url", @@ -92,3 +256,11 @@ def _update_migration_target_module_id(self): ) # Recompute 'target_module_id' field migrations._compute_target_module_branch_id() + + def open_next_module_branches(self): + self.ensure_one() + xml_id = "odoo_repository.odoo_module_branch_action" + action = self.env["ir.actions.actions"]._for_xml_id(xml_id) + action["name"] = _("Next versions") + action["domain"] = [("id", "in", self._get_next_module_branches().ids)] + return action diff --git a/odoo_repository_migration/models/odoo_module_branch_migration.py b/odoo_repository_migration/models/odoo_module_branch_migration.py index aea3d234..720f4706 100644 --- a/odoo_repository_migration/models/odoo_module_branch_migration.py +++ b/odoo_repository_migration/models/odoo_module_branch_migration.py @@ -85,13 +85,28 @@ class OdooModuleBranchMigration(models.Model): "same scope so it deserves a check during a migration." ), ) + renamed_to_module_id = fields.Many2one( + comodel_name="odoo.module", + compute="_compute_renamed_to_module_id", + string="Renamed to", + store=True, + index=True, + ) + replaced_by_module_id = fields.Many2one( + comodel_name="odoo.module", + compute="_compute_replaced_by_module_id", + string="Replaced by", + store=True, + index=True, + ) state = fields.Selection( selection=[ ("fully_ported", "Fully Ported"), ("migrate", "To migrate"), - ("port_commits", "Commits to port"), - ("review_migration", "Migration to review"), - ("moved_to_standard", "Moved to standard"), + ("port_commits", "Ported (missing commits?)"), + ("review_migration", "To review"), + ("replaced", "Replaced"), + ("moved_to_standard", "Moved to standard?"), ("moved_to_oca", "Moved to OCA"), ("moved_to_generic", "Moved to generic repo"), ], @@ -136,13 +151,24 @@ def _compute_display_name(self): f"{rec.source_branch_id.name} -> {rec.target_branch_id.name}" ) - @api.depends("module_branch_id", "migration_path_id") + @api.depends( + "module_branch_id", + "migration_path_id", + "replaced_by_module_id", + "renamed_to_module_id", + ) def _compute_target_module_branch_id(self): module_branch_model = self.env["odoo.module.branch"] for rec in self: + # Look for the right module technical name + module = ( + rec.replaced_by_module_id + or rec.renamed_to_module_id + or rec.module_branch_id.module_id + ) rec.target_module_branch_id = module_branch_model._find( rec.migration_path_id.target_branch_id, - rec.module_branch_id.module_id, + module, rec.module_branch_id.repository_id, domain=[("installable", "=", True)], ) @@ -180,10 +206,45 @@ def _compute_moved_to_generic(self): ) @api.depends( - "process", "pr_url", "moved_to_standard", "moved_to_oca", "moved_to_generic" + "module_branch_id.next_odoo_version_state", + "module_branch_id.next_odoo_version_module_id", + "target_branch_id", + ) + def _compute_renamed_to_module_id(self): + for rec in self: + rec.renamed_to_module_id = ( + rec.module_branch_id._renamed_to_module_in_target_version( + rec.target_branch_id + ) + ) + + @api.depends( + "module_branch_id.next_odoo_version_state", + "module_branch_id.next_odoo_version_module_id", + "target_branch_id", + ) + def _compute_replaced_by_module_id(self): + for rec in self: + rec.replaced_by_module_id = ( + rec.module_branch_id._replaced_by_module_in_target_version( + rec.target_branch_id + ) + ) + + @api.depends( + "replaced_by_module_id", + "process", + "pr_url", + "moved_to_standard", + "moved_to_oca", + "moved_to_generic", ) def _compute_state(self): for rec in self: + if rec.replaced_by_module_id: + # Module replaced by another one + rec.state = "replaced" + continue if rec.moved_to_standard: # Module moved to a standard repository (likely from OCA to # odoo/odoo, like 'l10n_eu_oss', 'knowledge', ...). @@ -214,6 +275,8 @@ def _compute_results_text(self): rec.results_text = pprint.pformat(rec.results) @api.depends( + "module_branch_id.last_scanned_commit", + "replaced_by_module_id", "repository_id.collect_migration_data", "last_source_scanned_commit", "last_target_scanned_commit", @@ -233,6 +296,9 @@ def _compute_migration_scan(self): # No migration scan for modules moved to Odoo/OCA/generic repo if rec.state and rec.state.startswith("moved_to"): continue + # No migration scan for modules replaced by another module + if rec.replaced_by_module_id: + continue if ( rec.last_source_scanned_commit != rec.module_branch_id.last_scanned_commit diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py index b2879e2a..96d2ed75 100644 --- a/odoo_repository_migration/models/odoo_repository.py +++ b/odoo_repository_migration/models/odoo_repository.py @@ -111,12 +111,33 @@ def _migration_create_jobs_scan_module(self, migration_path, modules_to_scan): return jobs def _scan_migration_module(self, migration_path_id, module_branch_id): - """Scan migration path for `module_branch_id`.""" + """Scan migration path for `module_branch_id`. + + The migration scan can only occur if: + - target module doesn't exist (and can be migrated) + - source and target modules share the same commits histories (able to + collect migration data) + + Also, a target module could have been renamed while sharing the commits history. + + But a module that has been replaced (different name, different commits + history, but providing the same feature) in next versions cannot be scanned. + Such module will get a migration status "Replaced". + """ module = self.env["odoo.module.branch"].browse(module_branch_id).exists() module.ensure_one() migration_path = ( self.env["odoo.migration.path"].browse(migration_path_id).exists() ) + # Skip migration scan if module is replaced in next versions + if module._replaced_by_module_in_target_version( + migration_path.target_branch_id + ): + return ( + f"{module.name} is now replaced by " + f"{module.next_odoo_version_module_id.name}, no need to collect " + "migration data." + ) # Check if module has already been migrated on target version but in a # different repository. If so, tune the scanner parameters to perform # the scan from current repo to new one. @@ -135,11 +156,15 @@ def _scan_migration_module(self, migration_path_id, module_branch_id): params = self._prepare_migration_scanner_parameters( migration_path, target_repository ) + module_names = [module.module_id.name] + if target_module: + if module.module_id != target_module.module_id: + module_names = [(module.module_id.name, target_module.module_id.name)] # Run the migration scan try: scanner = MigrationScannerOdooEnv(**params) return scanner.scan( - addons_path=module.addons_path, module_names=[module.module_id.name] + addons_path=module.addons_path, module_names=module_names ) except Exception as exc: raise RetryableJobError("Scanner error") from exc diff --git a/odoo_repository_migration/tests/test_odoo_module_branch.py b/odoo_repository_migration/tests/test_odoo_module_branch.py index 6efabeab..09bf8eb8 100644 --- a/odoo_repository_migration/tests/test_odoo_module_branch.py +++ b/odoo_repository_migration/tests/test_odoo_module_branch.py @@ -288,3 +288,103 @@ def test_migration_scan_target_module_moved_to_generic(self): self.assertTrue(mig.moved_to_generic) self.assertEqual(mig.state, "moved_to_generic") self.assertFalse(mig.migration_scan) + + def test_renamed_to_module_in_target_version(self): + self.odoo_repository.collect_migration_data = True + # Next version is 16.0 + next_branch = self.env["odoo.branch"].search( + [("sequence", "=", self.branch.sequence + 1)] + ) + # Create the target module + new_module = self.module.copy({"name": "new_module"}) + target_module_branch = self._create_odoo_module_branch( + new_module, + next_branch, + specific=False, + repository_branch_id=self.repo_branch.id, + last_scanned_commit="sha", + ) + # Generate migration data records + self.env["odoo.migration.path"].create( + { + "source_branch_id": self.branch.id, + "target_branch_id": next_branch.id, + } + ) + self._simulate_migration_scan( + "target_commit1", report={"process": "migrate", "results": {}} + ) + self.assertEqual(self.module_branch.next_odoo_version_id, next_branch) + # Module has been renamed starting from 16.0 + self.module_branch.next_odoo_version_state = "renamed" + self.module_branch.next_odoo_version_module_id = new_module + renamed_to_module = self.module_branch._renamed_to_module_in_target_version( + self.module_branch.next_odoo_version_id + ) + self.assertEqual(renamed_to_module, new_module) + # We target 17.0 to check if intermediate data in 16.0 is found + target_branch = self.env["odoo.branch"].search( + [("sequence", "=", self.branch.sequence + 2)] + ) + renamed_to_module = self.module_branch._renamed_to_module_in_target_version( + target_branch + ) + self.assertEqual(renamed_to_module, new_module) + # Check migration data + mig = self.module_branch.migration_ids + self.assertEqual(mig.renamed_to_module_id, new_module) + self.assertFalse(mig.replaced_by_module_id) + self.assertEqual(mig.target_module_branch_id, target_module_branch) + self.assertFalse(mig.last_target_scanned_commit) + self.assertEqual(mig.state, "migrate") + self.assertTrue(mig.migration_scan) + + def test_replaced_by_module_in_target_version(self): + self.odoo_repository.collect_migration_data = True + # Next version is 16.0 + next_branch = self.env["odoo.branch"].search( + [("sequence", "=", self.branch.sequence + 1)] + ) + # Create the target module + new_module = self.module.copy({"name": "new_module"}) + target_module_branch = self._create_odoo_module_branch( + new_module, + next_branch, + specific=False, + repository_branch_id=self.repo_branch.id, + last_scanned_commit="sha", + ) + # Generate migration data records + self.env["odoo.migration.path"].create( + { + "source_branch_id": self.branch.id, + "target_branch_id": next_branch.id, + } + ) + self._simulate_migration_scan( + "target_commit1", report={"process": "migrate", "results": {}} + ) + self.assertEqual(self.module_branch.next_odoo_version_id, next_branch) + # New module is replacing current one starting from 16.0 + self.module_branch.next_odoo_version_state = "replaced" + self.module_branch.next_odoo_version_module_id = new_module + replaced_by_module = self.module_branch._replaced_by_module_in_target_version( + self.module_branch.next_odoo_version_id + ) + self.assertEqual(replaced_by_module, new_module) + # We target 17.0 to check if intermediate data in 16.0 is found + target_branch = self.env["odoo.branch"].search( + [("sequence", "=", self.branch.sequence + 2)] + ) + replaced_by_module = self.module_branch._replaced_by_module_in_target_version( + target_branch + ) + self.assertEqual(replaced_by_module, new_module) + # Check migration data + mig = self.module_branch.migration_ids + self.assertEqual(mig.replaced_by_module_id, new_module) + self.assertFalse(mig.renamed_to_module_id) + self.assertEqual(mig.target_module_branch_id, target_module_branch) + self.assertFalse(mig.last_target_scanned_commit) + self.assertEqual(mig.state, "replaced") + self.assertFalse(mig.migration_scan) diff --git a/odoo_repository_migration/views/odoo_module_branch.xml b/odoo_repository_migration/views/odoo_module_branch.xml index a0cd9738..914d7dc9 100644 --- a/odoo_repository_migration/views/odoo_module_branch.xml +++ b/odoo_repository_migration/views/odoo_module_branch.xml @@ -8,8 +8,45 @@ odoo.module.branch +
+ +
+
+ Starting from version , + this module + + + + +
diff --git a/odoo_repository_migration/views/odoo_module_branch_migration.xml b/odoo_repository_migration/views/odoo_module_branch_migration.xml index 17eb9973..868b338d 100644 --- a/odoo_repository_migration/views/odoo_module_branch_migration.xml +++ b/odoo_repository_migration/views/odoo_module_branch_migration.xml @@ -13,13 +13,23 @@

- - - - - - - + + + + + + + + + + + From 523ed6c9d7c7f724db705340cdc29710ad2e1f0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Wed, 28 May 2025 13:54:38 +0200 Subject: [PATCH 32/50] odoo_repository_migration: collect migration data on specific repositories Now that multiple Odoo versions/branches can be set on a specific repository, we are able to collect the migration data of specific modules hosted in it. --- .../models/odoo_migration_path.py | 2 - .../models/odoo_module_branch.py | 5 +- .../models/odoo_module_branch_migration.py | 4 +- .../models/odoo_repository.py | 137 +++++++++++++----- .../tests/test_odoo_module_branch.py | 2 + odoo_repository_migration/utils/scanner.py | 6 +- 6 files changed, 109 insertions(+), 47 deletions(-) diff --git a/odoo_repository_migration/models/odoo_migration_path.py b/odoo_repository_migration/models/odoo_migration_path.py index 7dd314be..b3db3de6 100644 --- a/odoo_repository_migration/models/odoo_migration_path.py +++ b/odoo_repository_migration/models/odoo_migration_path.py @@ -14,13 +14,11 @@ class OdooMigrationPath(models.Model): source_branch_id = fields.Many2one( comodel_name="odoo.branch", ondelete="cascade", - domain=[("odoo_version", "=", True)], required=True, ) target_branch_id = fields.Many2one( comodel_name="odoo.branch", ondelete="cascade", - domain=[("odoo_version", "=", True)], required=True, ) diff --git a/odoo_repository_migration/models/odoo_module_branch.py b/odoo_repository_migration/models/odoo_module_branch.py index a33a66c3..bf13371b 100644 --- a/odoo_repository_migration/models/odoo_module_branch.py +++ b/odoo_repository_migration/models/odoo_module_branch.py @@ -51,10 +51,7 @@ def _compute_next_odoo_version_id(self): next_odoo_version = False if rec.branch_id: next_odoo_version = self.env["odoo.branch"].search( - [ - ("odoo_version", "=", True), - ("sequence", ">", rec.branch_id.sequence), - ], + [("sequence", ">", rec.branch_id.sequence)], limit=1, ) rec.next_odoo_version_id = next_odoo_version diff --git a/odoo_repository_migration/models/odoo_module_branch_migration.py b/odoo_repository_migration/models/odoo_module_branch_migration.py index 720f4706..515b0b05 100644 --- a/odoo_repository_migration/models/odoo_module_branch_migration.py +++ b/odoo_repository_migration/models/odoo_module_branch_migration.py @@ -318,8 +318,8 @@ def _compute_migration_scan(self): def push_scanned_data(self, module_branch_id, data): migration_path = self.env["odoo.migration.path"].search( [ - ("source_branch_id", "=", data["source_branch"]), - ("target_branch_id", "=", data["target_branch"]), + ("source_branch_id", "=", data["source_version"]), + ("target_branch_id", "=", data["target_version"]), ] ) values = { diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py index 96d2ed75..b3a23203 100644 --- a/odoo_repository_migration/models/odoo_repository.py +++ b/odoo_repository_migration/models/odoo_repository.py @@ -19,16 +19,25 @@ class OdooRepository(models.Model): default=False, ) - def _reset_scanned_commits(self, branches=None): - res = super()._reset_scanned_commits(branches) - if branches is None: - branches = [] - branches_ = ( - self.branch_ids.filtered(lambda br: br.branch_id.name in branches) - if branches - else self.branch_ids + def action_scan(self, branch_ids=None, force=False, raise_exc=True): + for rec in self: + # Scan only relevant branches regarding migration paths + rec_ctx = rec + if rec.specific: + rec_ctx = rec.with_context(strict_branches_scan=True) + super(OdooRepository, rec_ctx).action_scan( + branch_ids=branch_ids, force=force, raise_exc=raise_exc + ) + return True + + def _reset_scanned_commits(self, branch_ids=None): + res = super()._reset_scanned_commits(branch_ids=branch_ids) + if branch_ids is None: + branch_ids = self.branch_ids.branch_id.ids + repo_branches = self.branch_ids.filtered( + lambda rb: rb.branch_id.id in branch_ids ) - branches_.module_ids.migration_ids.sudo().write( + repo_branches.module_ids.migration_ids.sudo().write( { "last_source_scanned_commit": False, "last_target_scanned_commit": False, @@ -36,12 +45,14 @@ def _reset_scanned_commits(self, branches=None): ) return res - def _create_subsequent_jobs(self, branch, next_branches, all_branches, data): + def _create_subsequent_jobs( + self, version_branch, next_versions_branches, all_versions_branches, data + ): jobs = super()._create_subsequent_jobs( - branch, next_branches, all_branches, data + version_branch, next_versions_branches, all_versions_branches, data ) # Prepare migration scan jobs when its the last repository scan - last_scan = not next_branches + last_scan = not next_versions_branches if not last_scan: return jobs # Check if the addons_paths are compatible with 'oca_port' @@ -50,50 +61,91 @@ def _create_subsequent_jobs(self, branch, next_branches, all_branches, data): return jobs # Override to run the MigrationScanner once branches are scanned args = [] - if all_branches: + if all_versions_branches: + all_versions = [vb[0] for vb in all_versions_branches] # A strict scan of branches avoids unwanted migration scans # For instance if we are interested only by 14.0 and 17.0 branches, # this avoids to scan other migration paths like 15.0 -> 17.0 - strict_scan = self.env.context.get("strict_branches_scan") + # NOTE: a strict scan always occurs on specific repositories + strict_scan = self.env.context.get("strict_branches_scan") or self.specific args = [ "&" if strict_scan else "|", - ("source_branch_id", "in", all_branches), - ("target_branch_id", "in", all_branches), + ("source_branch_id", "in", all_versions), + ("target_branch_id", "in", all_versions), ] migration_paths = self.env["odoo.migration.path"].search(args) # Launch one job for all migration_paths if migration_paths: + # Migration paths parameter containing the migration path ID + + # the Odoo versions and branches to scan. + # E.g. {MIG_PATH_ID: [('14.0', 'master'), ('18.0', '18.0-mig')], ...} + migration_paths_param = {} + for migration_path in migration_paths: + source_rb = self.branch_ids.filtered( + lambda rb: rb.branch_id == migration_path.source_branch_id + ) + target_rb = self.branch_ids.filtered( + lambda rb: rb.branch_id == migration_path.target_branch_id + ) + # Need the two Odoo versions of the migration path available + # in the scanned repository + if not source_rb or not target_rb: + continue + # Build list of tuples (Odoo version, branch name) corresponding + # to the migration path + versions_branches = [ + ( + source_rb.branch_id.name, + source_rb.cloned_branch or source_rb.branch_id.name, + ), + ( + target_rb.branch_id.name, + target_rb.cloned_branch or target_rb.branch_id.name, + ), + ] + migration_paths_param[migration_path.id] = versions_branches + delayable = self.delayable( description=f"Collect {self.display_name} migration data", identity_key=identity_exact, ) - job = delayable._scan_migration_paths(migration_paths.ids) + job = delayable._scan_migration_paths(migration_paths_param) jobs.append(job) return jobs - def _scan_migration_paths(self, migration_path_ids): + def _scan_migration_paths(self, migration_paths_param): """Scan repository branches to collect modules migration data. Spawn one job per module to scan. """ self.ensure_one() jobs = [] - migration_paths = ( - self.env["odoo.migration.path"].browse(migration_path_ids).exists() - ) - for migration_path in migration_paths: + for migration_path_id in migration_paths_param: + versions_branches = migration_paths_param[migration_path_id] + migration_path = ( + self.env["odoo.migration.path"] + .browse( + # Job encodes dict key as string => convert it to integer + int(migration_path_id) + ) + .exists() + ) + if not migration_path: + continue modules_to_scan = self._migration_get_modules_to_scan(migration_path) if modules_to_scan: jobs.extend( self._migration_create_jobs_scan_module( - migration_path, modules_to_scan + migration_path, versions_branches, modules_to_scan ) ) if jobs: chain(*jobs).delay() return True - def _migration_create_jobs_scan_module(self, migration_path, modules_to_scan): + def _migration_create_jobs_scan_module( + self, migration_path, versions_branches, modules_to_scan + ): jobs = [] mig_path = ( migration_path.source_branch_id.name, @@ -106,11 +158,15 @@ def _migration_create_jobs_scan_module(self, migration_path, modules_to_scan): ), identity_key=identity_exact, ) - job = delayable._scan_migration_module(migration_path.id, module.id) + job = delayable._scan_migration_module( + migration_path.id, versions_branches, module.id + ) jobs.append(job) return jobs - def _scan_migration_module(self, migration_path_id, module_branch_id): + def _scan_migration_module( + self, migration_path_id, versions_branches, module_branch_id + ): """Scan migration path for `module_branch_id`. The migration scan can only occur if: @@ -154,7 +210,7 @@ def _scan_migration_module(self, migration_path_id, module_branch_id): f"{target_repository.display_name}." ) params = self._prepare_migration_scanner_parameters( - migration_path, target_repository + versions_branches, target_repository ) module_names = [module.module_id.name] if target_module: @@ -164,7 +220,9 @@ def _scan_migration_module(self, migration_path_id, module_branch_id): try: scanner = MigrationScannerOdooEnv(**params) return scanner.scan( - addons_path=module.addons_path, module_names=module_names + addons_path=module.addons_path, + target_addons_path=target_module.addons_path or module.addons_path, + module_names=module_names, ) except Exception as exc: raise RetryableJobError("Scanner error") from exc @@ -172,7 +230,8 @@ def _scan_migration_module(self, migration_path_id, module_branch_id): def _migration_get_modules_to_scan(self, migration_path): """Return `odoo.module.branch` records that need a migration scan.""" self.ensure_one() - return self.env["odoo.module.branch"].search( + mb_model = self.env["odoo.module.branch"] + modules = mb_model.search( [ ( "repository_id", @@ -183,21 +242,27 @@ def _migration_get_modules_to_scan(self, migration_path): ("migration_scan", "=", True), ] ) + module_ids = [] + for module in modules: + migration = module.migration_ids.filtered( + lambda mig: mig.migration_path_id == migration_path + ) + if migration and not migration.migration_scan: + # Skip module that do not need a scan for the given migration path + continue + module_ids.append(module.id) + return mb_model.browse(module_ids) def _prepare_migration_scanner_parameters( self, migration_path, target_repository=None ): ir_config = self.env["ir.config_parameter"] repositories_path = ir_config.sudo().get_param(self._repositories_path_key) - mig_path = ( - migration_path.source_branch_id.name, - migration_path.target_branch_id.name, - ) params = { "org": self.org_id.name, "name": self.name, "clone_url": self.clone_url, - "migration_path": mig_path, + "migration_path": migration_path, "repositories_path": repositories_path, "repo_type": self.repo_type, "ssh_key": self.ssh_key_id.private_key, @@ -221,10 +286,10 @@ def _pre_create_or_update_module_branch(self, rec, values, raw_data): values["migration_ids"] = [] for mig in migrations: source_branch = self.env["odoo.branch"].search( - [("odoo_version", "=", True), ("name", "=", mig["source_branch"])] + [("name", "=", mig["source_branch"])] ) target_branch = self.env["odoo.branch"].search( - [("odoo_version", "=", True), ("name", "=", mig["target_branch"])] + [("name", "=", mig["target_branch"])] ) if not source_branch or not target_branch: # Such branches are not configured on this instance, skip diff --git a/odoo_repository_migration/tests/test_odoo_module_branch.py b/odoo_repository_migration/tests/test_odoo_module_branch.py index 09bf8eb8..0797d32f 100644 --- a/odoo_repository_migration/tests/test_odoo_module_branch.py +++ b/odoo_repository_migration/tests/test_odoo_module_branch.py @@ -38,7 +38,9 @@ def _simulate_migration_scan(self, target_commit, report=None): """Helper method that pushes scanned migration data.""" data = { "module": self.module_branch.module_name, + "source_version": self.branch.name, "source_branch": self.branch.name, + "target_version": self.branch2.name, "target_branch": self.branch2.name, "source_commit": self.module_branch.last_scanned_commit, "target_commit": target_commit, diff --git a/odoo_repository_migration/utils/scanner.py b/odoo_repository_migration/utils/scanner.py index c4f3eb81..a5734fcc 100644 --- a/odoo_repository_migration/utils/scanner.py +++ b/odoo_repository_migration/utils/scanner.py @@ -70,13 +70,13 @@ def _get_odoo_module_branch_migration_id( return migration.id def _get_odoo_module_branch_migration_data( - self, repo_id: int, module: str, source_branch: str, target_branch: str + self, repo_id: int, module: str, source_version: str, target_version: str ) -> dict: args = [ ("module_branch_id.repository_id", "=", repo_id), ("module_id", "=", module), - ("source_branch_id", "=", source_branch), - ("target_branch_id", "=", target_branch), + ("source_branch_id", "=", source_version), + ("target_branch_id", "=", target_version), ] migration = self.env["odoo.module.branch.migration"].search(args) if migration: From a7be94e4459354123cf77dfa2e8e2075eb726262 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Sun, 14 Sep 2025 11:17:45 +0200 Subject: [PATCH 33/50] odoo_repository_migration: move replaced/renamed modules data in their own data model --- odoo_repository_migration/__manifest__.py | 3 +- .../migrations/16.0.1.3.0/post-migration.py | 35 ++++++ odoo_repository_migration/models/__init__.py | 1 + .../models/odoo_module_branch.py | 88 +++------------ .../models/odoo_module_branch_migration.py | 8 +- .../models/odoo_module_branch_timeline.py | 102 ++++++++++++++++++ .../security/ir.model.access.csv | 2 + .../tests/test_odoo_module_branch.py | 26 +++-- .../views/odoo_module_branch.xml | 29 +---- .../views/odoo_module_branch_migration.xml | 3 +- .../views/odoo_module_branch_timeline.xml | 102 ++++++++++++++++++ 11 files changed, 286 insertions(+), 113 deletions(-) create mode 100644 odoo_repository_migration/migrations/16.0.1.3.0/post-migration.py create mode 100644 odoo_repository_migration/models/odoo_module_branch_timeline.py create mode 100644 odoo_repository_migration/views/odoo_module_branch_timeline.xml diff --git a/odoo_repository_migration/__manifest__.py b/odoo_repository_migration/__manifest__.py index 9625b7aa..26385d82 100644 --- a/odoo_repository_migration/__manifest__.py +++ b/odoo_repository_migration/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Odoo Repository Migration Data", "summary": "Collect modules migration data for Odoo Repositories.", - "version": "16.0.1.2.0", + "version": "16.0.1.3.0", "category": "Tools", "author": "Camptocamp, Odoo Community Association (OCA)", "website": "https://github.com/camptocamp/odoo-repository", @@ -13,6 +13,7 @@ "views/odoo_migration_path.xml", "views/odoo_module_branch.xml", "views/odoo_module_branch_migration.xml", + "views/odoo_module_branch_timeline.xml", "views/odoo_repository.xml", ], "installable": True, diff --git a/odoo_repository_migration/migrations/16.0.1.3.0/post-migration.py b/odoo_repository_migration/migrations/16.0.1.3.0/post-migration.py new file mode 100644 index 00000000..af988af2 --- /dev/null +++ b/odoo_repository_migration/migrations/16.0.1.3.0/post-migration.py @@ -0,0 +1,35 @@ +# Copyright 2025 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +import logging + +from odoo import SUPERUSER_ID, api + +_logger = logging.getLogger(__name__) + + +def migrate(cr, version): + if not version: + return + env = api.Environment(cr, SUPERUSER_ID, {}) + migrate_odoo_module_branch_timelines(env) + + +def migrate_odoo_module_branch_timelines(env): + _logger.info("Migrate Odoo module timelines to 'odoo.module.branch.timeline'...") + query = """ + SELECT id, next_odoo_version_state, next_odoo_version_module_id + FROM odoo_module_branch + WHERE next_odoo_version_state != 'same'; + """ + env.cr.execute(query) + rows = env.cr.dictfetchall() + vals_list = [] + for row in rows: + vals = { + "module_branch_id": row["id"], + "state": row["next_odoo_version_state"], + "next_module_id": row["next_odoo_version_module_id"], + } + vals_list.append(vals) + env["odoo.module.branch.timeline"].create(vals_list) diff --git a/odoo_repository_migration/models/__init__.py b/odoo_repository_migration/models/__init__.py index db7baee9..75bb5828 100644 --- a/odoo_repository_migration/models/__init__.py +++ b/odoo_repository_migration/models/__init__.py @@ -1,4 +1,5 @@ from . import odoo_migration_path from . import odoo_module_branch_migration +from . import odoo_module_branch_timeline from . import odoo_module_branch from . import odoo_repository diff --git a/odoo_repository_migration/models/odoo_module_branch.py b/odoo_repository_migration/models/odoo_module_branch.py index bf13371b..62e40d81 100644 --- a/odoo_repository_migration/models/odoo_module_branch.py +++ b/odoo_repository_migration/models/odoo_module_branch.py @@ -7,27 +7,10 @@ class OdooModuleBranch(models.Model): _inherit = "odoo.module.branch" - next_odoo_version_id = fields.Many2one( - comodel_name="odoo.branch", - compute="_compute_next_odoo_version_id", - ) - next_odoo_version_state = fields.Selection( - selection=[ - ("same", "is named the same"), - ("renamed", "has been renamed to"), - ("replaced", "has been replaced by"), - ], - inverse="_inverse_next_odoo_version_fields", - default="same", - required=True, - index=True, - ) - next_odoo_version_module_id = fields.Many2one( - comodel_name="odoo.module", - ondelete="restrict", - inverse="_inverse_next_odoo_version_fields", - string="Next Odoo Version Module", - index=True, + timeline_ids = fields.One2many( + comodel_name="odoo.module.branch.timeline", + inverse_name="module_branch_id", + string="Timeline", ) next_odoo_version_module_branch_id = fields.Many2one( comodel_name="odoo.module.branch", @@ -45,73 +28,34 @@ class OdooModuleBranch(models.Model): help="Technical field telling if this module is elligible for a migration scan.", ) - @api.depends("branch_id") - def _compute_next_odoo_version_id(self): - for rec in self: - next_odoo_version = False - if rec.branch_id: - next_odoo_version = self.env["odoo.branch"].search( - [("sequence", ">", rec.branch_id.sequence)], - limit=1, - ) - rec.next_odoo_version_id = next_odoo_version - - @api.depends("next_odoo_version_id", "next_odoo_version_module_id") + @api.depends("branch_id.next_id", "timeline_ids") def _compute_next_odoo_version_module_branch_id(self): for rec in self: rec.next_odoo_version_module_branch_id = False # Stop there if no next version - if not rec.next_odoo_version_id: + if not rec.branch_id.next_id: continue # Look for the next available version for this module name rec.next_odoo_version_module_branch_id = self.search( [ - ("branch_id", "=", rec.next_odoo_version_id.id), + ("branch_sequence", ">=", rec.branch_id.next_id.sequence), ("module_id", "=", rec.module_id.id), ], + order="branch_sequence", limit=1, ) # Stop there if no renaming/relacement - if not rec.next_odoo_version_module_id: + if not rec.timeline_ids: continue rec.next_odoo_version_module_branch_id = self.search( [ - ("branch_id", "=", rec.next_odoo_version_id.id), - ("module_id", "=", rec.next_odoo_version_module_id.id), + ("branch_sequence", ">=", rec.branch_id.next_id.sequence), + ("module_id", "=", rec.timeline_ids.next_module_id.id), ], + order="branch_sequence", limit=1, ) - def _inverse_next_odoo_version_fields(self): - # Reset selected module if the module name doesn't change with next version - if self.next_odoo_version_state == "same": - self.next_odoo_version_module_id = False - # If module is renamed or replaced in next Odoo version, we reset the - # last target scan commits on all impacted migration paths. - # E.g. - # if a module on 17.0 is set as renamed starting from 18.0, - # all migration paths of this module targetting versions >= 18.0 - # should re-trigger a migration scan. - else: - migrations = ( - self.env["odoo.module.branch.migration"] - .search( - [ - ("module_id", "=", self.module_id.id), - ( - "target_branch_id.sequence", - ">=", - self.next_odoo_version_id.sequence, - ), - ] - ) - .sudo() - ) - migrations.last_target_scanned_commit = False - migrations._compute_renamed_to_module_id() - migrations._compute_replaced_by_module_id() - migrations._compute_state() - def _replaced_by_module_in_target_version(self, target_branch): """Return the module replacing current one in last module versions. @@ -126,8 +70,8 @@ def _replaced_by_module_in_target_version(self, target_branch): for module in modules.sorted( key=lambda mod: mod.branch_id.sequence, reverse=True ): - if module.next_odoo_version_state == "replaced": - return module.next_odoo_version_module_id + if module.timeline_ids.state == "replaced": + return module.timeline_ids.next_module_id return self.env["odoo.module"] def _renamed_to_module_in_target_version(self, target_branch): @@ -144,8 +88,8 @@ def _renamed_to_module_in_target_version(self, target_branch): for module in modules.sorted( key=lambda mod: mod.branch_id.sequence, reverse=True ): - if module.next_odoo_version_state == "renamed": - return module.next_odoo_version_module_id + if module.timeline_ids.state == "renamed": + return module.timeline_ids.next_module_id return self.env["odoo.module"] def _get_next_versions(self, target_branch): diff --git a/odoo_repository_migration/models/odoo_module_branch_migration.py b/odoo_repository_migration/models/odoo_module_branch_migration.py index 515b0b05..24980f0e 100644 --- a/odoo_repository_migration/models/odoo_module_branch_migration.py +++ b/odoo_repository_migration/models/odoo_module_branch_migration.py @@ -206,8 +206,8 @@ def _compute_moved_to_generic(self): ) @api.depends( - "module_branch_id.next_odoo_version_state", - "module_branch_id.next_odoo_version_module_id", + "module_branch_id.timeline_ids.state", + "module_branch_id.timeline_ids.next_module_id", "target_branch_id", ) def _compute_renamed_to_module_id(self): @@ -219,8 +219,8 @@ def _compute_renamed_to_module_id(self): ) @api.depends( - "module_branch_id.next_odoo_version_state", - "module_branch_id.next_odoo_version_module_id", + "module_branch_id.timeline_ids.state", + "module_branch_id.timeline_ids.next_module_id", "target_branch_id", ) def _compute_replaced_by_module_id(self): diff --git a/odoo_repository_migration/models/odoo_module_branch_timeline.py b/odoo_repository_migration/models/odoo_module_branch_timeline.py new file mode 100644 index 00000000..b924a991 --- /dev/null +++ b/odoo_repository_migration/models/odoo_module_branch_timeline.py @@ -0,0 +1,102 @@ +# Copyright 2025 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo import api, fields, models + + +class OdooModuleBranchTimeline(models.Model): + _name = "odoo.module.branch.timeline" + _description = "Odoo Module Timeline (renaming/replacement)" + _order = "odoo_version_sequence" + + module_branch_id = fields.Many2one( + string="Module", + comodel_name="odoo.module.branch", + required=True, + index=True, + ) + org_id = fields.Many2one( + string="Organization", + related="module_branch_id.org_id", + store=True, + index=True, + ) + repository_id = fields.Many2one( + string="Repository", + related="module_branch_id.repository_id", + store=True, + index=True, + ) + odoo_version_id = fields.Many2one( + string="Starting from version", + related="module_branch_id.branch_id.next_id", + store=True, + index=True, + ) + odoo_version_sequence = fields.Integer( + related="odoo_version_id.sequence", + store=True, + ) + state = fields.Selection( + selection=[ + ("renamed", "has been renamed to"), + ("replaced", "has been replaced by"), + ], + inverse="_inverse_next_fields", + default="renamed", + required=True, + index=True, + help=( + "Renamed: modules still share the same Git history (it allows to " + "check commits that could be ported)\n" + "Replaced: module has been replaced (or merged) by another one that " + "fulfill the same feature" + ), + ) + next_module_id = fields.Many2one( + string="New module name", + comodel_name="odoo.module", + inverse="_inverse_next_fields", + ondelete="restrict", + index=True, + ) + next_module_branch_id = fields.Many2one( + string="New module", + related="module_branch_id.next_odoo_version_module_branch_id", + ) + note = fields.Html() + + @api.depends("odoo_version_id", "module_branch_id", "next_module_id") + def _compute_display_name(self): + for rec in self: + rec.display_name = ( + f"[{rec.odoo_version_id.name}] " + f"{rec.module_branch_id.module_id.name} > {rec.next_module_id.name}" + ) + + def _inverse_next_fields(self): + # When a module is renamed or replaced, we reset the + # last target scan commits on all impacted migration paths. + # E.g. + # if a module on 17.0 is set as renamed starting from 18.0, + # all migration paths of this module targetting versions >= 18.0 + # should re-trigger a migration scan. + for rec in self: + migrations = ( + self.env["odoo.module.branch.migration"] + .search( + [ + ("module_id", "=", rec.module_branch_id.module_id.id), + ( + "target_branch_id.sequence", + ">=", + rec.odoo_version_id.sequence, + ), + ] + ) + .sudo() + ) + migrations.last_target_scanned_commit = False + migrations._compute_renamed_to_module_id() + migrations._compute_replaced_by_module_id() + migrations._compute_state() diff --git a/odoo_repository_migration/security/ir.model.access.csv b/odoo_repository_migration/security/ir.model.access.csv index 7b021329..fd58e05f 100644 --- a/odoo_repository_migration/security/ir.model.access.csv +++ b/odoo_repository_migration/security/ir.model.access.csv @@ -2,3 +2,5 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_odoo_migration_path_user,odoo_migration_path_user,model_odoo_migration_path,odoo_repository.group_odoo_repository_user,1,0,0,0 access_odoo_migration_path_manager,odoo_migration_path_manager,model_odoo_migration_path,odoo_repository.group_odoo_repository_manager,1,0,1,1 access_odoo_module_branch_migration_user,odoo_module_branch_migration_user,model_odoo_module_branch_migration,odoo_repository.group_odoo_repository_user,1,0,0,0 +access_odoo_module_branch_timeline_user,odoo_module_branch_timeline_user,model_odoo_module_branch_timeline,odoo_repository.group_odoo_repository_user,1,0,0,0 +access_odoo_module_branch_timeline_manager,odoo_module_branch_timeline_manager,model_odoo_module_branch_timeline,odoo_repository.group_odoo_repository_manager,1,1,1,1 diff --git a/odoo_repository_migration/tests/test_odoo_module_branch.py b/odoo_repository_migration/tests/test_odoo_module_branch.py index 0797d32f..b5b38356 100644 --- a/odoo_repository_migration/tests/test_odoo_module_branch.py +++ b/odoo_repository_migration/tests/test_odoo_module_branch.py @@ -297,6 +297,7 @@ def test_renamed_to_module_in_target_version(self): next_branch = self.env["odoo.branch"].search( [("sequence", "=", self.branch.sequence + 1)] ) + self.assertEqual(self.branch.next_id, next_branch) # Create the target module new_module = self.module.copy({"name": "new_module"}) target_module_branch = self._create_odoo_module_branch( @@ -316,12 +317,16 @@ def test_renamed_to_module_in_target_version(self): self._simulate_migration_scan( "target_commit1", report={"process": "migrate", "results": {}} ) - self.assertEqual(self.module_branch.next_odoo_version_id, next_branch) # Module has been renamed starting from 16.0 - self.module_branch.next_odoo_version_state = "renamed" - self.module_branch.next_odoo_version_module_id = new_module + self.module_branch.timeline_ids.create( + { + "module_branch_id": self.module_branch.id, + "state": "renamed", + "next_module_id": new_module.id, + } + ) renamed_to_module = self.module_branch._renamed_to_module_in_target_version( - self.module_branch.next_odoo_version_id + next_branch ) self.assertEqual(renamed_to_module, new_module) # We target 17.0 to check if intermediate data in 16.0 is found @@ -347,6 +352,7 @@ def test_replaced_by_module_in_target_version(self): next_branch = self.env["odoo.branch"].search( [("sequence", "=", self.branch.sequence + 1)] ) + self.assertEqual(self.branch.next_id, next_branch) # Create the target module new_module = self.module.copy({"name": "new_module"}) target_module_branch = self._create_odoo_module_branch( @@ -366,12 +372,16 @@ def test_replaced_by_module_in_target_version(self): self._simulate_migration_scan( "target_commit1", report={"process": "migrate", "results": {}} ) - self.assertEqual(self.module_branch.next_odoo_version_id, next_branch) # New module is replacing current one starting from 16.0 - self.module_branch.next_odoo_version_state = "replaced" - self.module_branch.next_odoo_version_module_id = new_module + self.module_branch.timeline_ids.create( + { + "module_branch_id": self.module_branch.id, + "state": "replaced", + "next_module_id": new_module.id, + } + ) replaced_by_module = self.module_branch._replaced_by_module_in_target_version( - self.module_branch.next_odoo_version_id + next_branch ) self.assertEqual(replaced_by_module, new_module) # We target 17.0 to check if intermediate data in 16.0 is found diff --git a/odoo_repository_migration/views/odoo_module_branch.xml b/odoo_repository_migration/views/odoo_module_branch.xml index 914d7dc9..302deea1 100644 --- a/odoo_repository_migration/views/odoo_module_branch.xml +++ b/odoo_repository_migration/views/odoo_module_branch.xml @@ -9,44 +9,19 @@
+
-
- Starting from version , - this module - - - - -
diff --git a/odoo_repository_migration/views/odoo_module_branch_migration.xml b/odoo_repository_migration/views/odoo_module_branch_migration.xml index 868b338d..15b53d0a 100644 --- a/odoo_repository_migration/views/odoo_module_branch_migration.xml +++ b/odoo_repository_migration/views/odoo_module_branch_migration.xml @@ -145,8 +145,9 @@ diff --git a/odoo_repository_migration/views/odoo_module_branch_timeline.xml b/odoo_repository_migration/views/odoo_module_branch_timeline.xml new file mode 100644 index 00000000..60ec528a --- /dev/null +++ b/odoo_repository_migration/views/odoo_module_branch_timeline.xml @@ -0,0 +1,102 @@ + + + + + + odoo.module.branch.timeline.form + odoo.module.branch.timeline + + + + + + + + + + + + + + + + + + + + odoo.module.branch.timeline.tree + odoo.module.branch.timeline + + + + + + + + + + + + odoo.module.branch.timeline.search + odoo.module.branch.timeline + search + + + + + + + + + + + + + + + + + + + + + + Timelines + ir.actions.act_window + odoo.module.branch.timeline + + {'search_default_group_by_org_id': 1} + + + + + From d74c7faa8dbba44e334cf731ad5b351db28c0ade Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Wed, 3 Dec 2025 03:33:36 +0000 Subject: [PATCH 34/50] [UPD] README.rst --- odoo_repository_migration/README.rst | 42 +++++++++++----- .../static/description/index.html | 49 ++++++++++++------- 2 files changed, 62 insertions(+), 29 deletions(-) diff --git a/odoo_repository_migration/README.rst b/odoo_repository_migration/README.rst index cafdf9b9..3f2df64a 100644 --- a/odoo_repository_migration/README.rst +++ b/odoo_repository_migration/README.rst @@ -1,3 +1,7 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + ============================== Odoo Repository Migration Data ============================== @@ -7,20 +11,26 @@ Odoo Repository Migration Data !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:4705947f581f1953f9c146b61253c9ebd83975867442c894ece00ac3c5f142e0 + !! source digest: sha256:ca1a8de995fd9b4e82e491087c7f380a6a17ae31d175e8709f2ddb43fd9f95cb !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status :alt: Beta -.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png +.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 -.. |badge3| image:: https://img.shields.io/badge/github-camptocamp%2Fodoo--repository-lightgray.png?logo=github - :target: https://github.com/camptocamp/odoo-repository/tree/16.0/odoo_repository_migration - :alt: camptocamp/odoo-repository - -|badge1| |badge2| |badge3| +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fodoo--repository-lightgray.png?logo=github + :target: https://github.com/OCA/odoo-repository/tree/16.0/odoo_repository_migration + :alt: OCA/odoo-repository +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/odoo-repository-16-0/odoo-repository-16-0-odoo_repository_migration + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/odoo-repository&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| This module collects modules migration data from Odoo repositories. @@ -32,10 +42,10 @@ This module collects modules migration data from Odoo repositories. Bug Tracker =========== -Bugs are tracked on `GitHub Issues `_. +Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -56,6 +66,16 @@ Contributors Maintainers ~~~~~~~~~~~ -This module is part of the `camptocamp/odoo-repository `_ project on GitHub. +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/odoo-repository `_ project on GitHub. -You are welcome to contribute. +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/odoo_repository_migration/static/description/index.html b/odoo_repository_migration/static/description/index.html index cc60c0b7..6ba7c13c 100644 --- a/odoo_repository_migration/static/description/index.html +++ b/odoo_repository_migration/static/description/index.html @@ -1,18 +1,18 @@ - -Odoo Repository Migration Data +README.rst -
-

Odoo Repository Migration Data

+
+ + +Odoo Community Association + +
+

Odoo Repository Migration Data

-

Beta License: AGPL-3 camptocamp/odoo-repository

+

Beta License: AGPL-3 OCA/odoo-repository Translate me on Weblate Try me on Runboat

This module collects modules migration data from Odoo repositories.

Table of contents

@@ -384,32 +389,40 @@

Odoo Repository Migration Data

-

Bug Tracker

-

Bugs are tracked on GitHub Issues. +

Bug Tracker

+

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • Camptocamp
-

Contributors

+

Contributors

-

Maintainers

-

This module is part of the camptocamp/odoo-repository project on GitHub.

-

You are welcome to contribute.

+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/odoo-repository project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
From d9ce6fcc8c8f27563e586f80206c87f0d00e6948 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Wed, 3 Dec 2025 03:33:36 +0000 Subject: [PATCH 35/50] [ADD] icon.png --- .../static/description/icon.png | Bin 0 -> 10254 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 odoo_repository_migration/static/description/icon.png diff --git a/odoo_repository_migration/static/description/icon.png b/odoo_repository_migration/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1dcc49c24f364e9adf0afbc6fc0bac6dbecdeb11 GIT binary patch literal 10254 zcmbt)WmufcvhH9Zc!C8B?l8#UE&&o;gF7=g3=D(IAOS+K1lK^25Zv7%L4sRw_uvvF z*qyAk?>c**=lnR&y+1yw{;I3Hy6Ua2{<d0kcR+VvBo; zA_X`>;1;xAPL9rQqFxd#f5{a^zW*uaW+r3+U{|fRunu`GZhy$X z8_|Zi{zd#vIokczl8Xh*4Wi@i0+C?Rg1AB5VOEg8B>buLFCi~r5DPd2ED7QP2>^LO zKpr7+?*I1bPaFSLLEa0l2$tj*;u8Qtc=&(RUc*VK@ zjIN{I--GfO@vl+&r^eqy_BZ3dndN_PDzMc*W^!?dIsWAWU@LBjBg6^f4F6*!-hUYh zY$Xb}gF8b0%S1Ac@c%Rs()UCiEu3v6SiFE>h_!{gBb-H2{e=wB5o!YkT0>#LKZFw$ z?CuD0Gvfsb(|XbVxx0AL0%`gG2X+6|f;jiTHU9shtjoW-{2!| zMN*WuOj6elhD4zqgjNpX>F#JP{)hAbenX<+FPr>7jXM&q{|x+pbj8cU<=>Ej zWE1_%qoFVzDAZB%g@v<+1ud%<#2E~ML11jOV5pUZoXktGmzB38%te^i-3o9i$lge>z>tBcK|P2K0H9w{l#|i%$~egM)Ys{q>p<9yaE*%v2cy1wXE{AXqG1_b znfyg@Fq*e@yC)^(@$R*j^E;skyEM6pmL$1ctg*mWiWM&q1{nj>E^)Odw$RPr zhjesSk}k}@-e_%uZTy0t_*TJD&6%*HV0KH>xE@oBex6CL@`Ty3nH_2OF#M?6j(j|9 znRKGSfp3Q2i+|>}w?>8g$>r`|OcvG5r;p)z8DO8+O>EvYQ=_~`p}9!ReUEjUnNL@6 z+C*aoo67(sd|7QgW54@V9Y8PnBW$Q+7ZsRFA}Vj*viA!yWUfb!s*yJi6JKsXZCH4j z*B%nJpad-DDvJ8d>xrxkkh6A}i7V3nULqHCiG~|)YY6{NE3M}c^s#PQhzhsJUf^QW zR+F;up-dN*!)M1ZYl@d0HoqfVD2PNiQcPdzq4NDKO!8mUl{!t*ntBg_+-+lRlI0~Lr>5v!PiQj|hD7B-YFIs~6hIY*R6USZA zlb}=UxqxpSzIsL3pPmiuixCN|3LFBd?0Ih8Y6GWQ;U>dkdXtQaQ&8H|TGAQbuHY=F z_R83&B{1_hP7L#$^eAe?GPB_83y#HZKTwD>e-@E2P>Gk$BBb9|Ivfmdp za~s>3=aj(;xmz8n)sI}uFO$|C>0CZbcTY$Bq6~L-Bc9=vl@X#0S~Q@j8iKzuPeQE_ zQSI)wNz~CvJ>!%QszoCfUm9}h^DL!WYAN|FtMO#kpDXq74sYC87(uvv*jiCjV?Ta& zgO1D0OP3TEN3YnBpD6GnmsEolzEbGM{&VlTz_)J(o{nl0+TmNt{xL%L6G&UR$^aYC zQOA#W7R%9JsC5oTZJE>_?!Ci}mNH{0ObyUd%Q!k%5J8Z`8sR!m`~|Taje`(bLD7=a z-{-=d7w;k@DIrgU{I@K}eN`>S**Lg<@ChAf$M(&kV9TLUixqFQ>YoYHrI!K#R6`S> z%?d5hQ@&;Gje<|uRQZb%Hhibocl9(buI?=0aZW{JYXx?ZS@Lr%G8L<d+riEi2~+{HfHK{K^VrGYNi{2-WJOiC>Pz?f*)cxKCl>1H1=$jb!^ zpmYw>eoiM0Hy7$xbbX_e5o*+{7T2&-t%-h4i7MMo;k|tSqQAeNkwHS9hWY#EV7r3| zTmOmN{;b9OUZpp`LP(I9Wo%R#$b6YdH7GD4*p6>a2N2A04pQ*n;INQMh%+mj;x7>S z_(H?uJ^n!r1)kJH1*s+%$al#?C^Cw{H@RA^QGB=Dubyc)XUaY>f`(VKTlIO-YNCp{1n zOl*>jT?Dtf5fD$DY-j&B*Xmn|2-u2OB zBL@-lFs5lhcQKXBR*cIXmi%~EJcc^5#Xpg!E^A6sXf1#$qJGRpmU~A zcdj-cvBfx(fIRAMU(1obztJR%I7v3R-%$#~r!0sS^I(iC*5i6296*88A7I=_JhU3p zya!aCti0R5*RFT%LW0R|;u&oJ6=P-c$le4J0bi}u!!@;xzao|l6fJ{;Mld9hGhrJg zr_B)=4yktp)yPB@tCC_L9h1>GzXD6DA!W7xt{1)8!07~gONkEWC8@y%lciB{9ojy) zWm$drJ_9uVJ>Q$-`@q%OM7_S>(K=__CGYB~@@mE^Z=eT|x0Rv?Z-N)LLWR zod*Zy3v)iMX@usPX-OKBDgC8yq?fMhqf8H)A&C)Hi29YFn!NVf5!J0-F{wC&L5-3`#id=4?=2>Zp6Pdu4N6#bG&atu7 z8IET&ciXy_Tp4YjMx3yIAbw#_e2#jgGJ~ogkv-|M7|%Gio%2@mnS89NKUOM#Bzg4_ z9e9oN;^m>G*#?)AawODi6YckRPmkSKD_4b4WFpj|@|eS!B0WN@?QscYzTH`~6e%iz z!z1>ps)CG37%(E=kZ_>re)@ODv^0^=rWU^*m;6M&gD10EYImO98JVabRe5{#wrogYUKPB@_(#e7Ej9_x;n1oHDj5GawU)A&1hWj|HzJB(q{vMTX>jOW;Jz zBsW&SqTaR7!NXXg_A}$XnFpg_n)Zi;{e9eb*k|b(y$a}12boJ7rqQXQpVhU8HxHTl zt8Ln!KLFyfq!%}hdMXle^qajw2g6S{z&7tQ6J(w9 z3+!HTO{_TqM{9o$RR~lKFf4b4(xLUP?QG;McNFQc_Yd_mig9Ejy9%q~Ye>rIn3};U z)w&1@QCK;cC(;x0G&YuSad+>{c@ZsFJcUdcs@PP-x{mrO)|6_#CjMlXsMJx;Cr?FF zVFrlt@$Z-Ll^*7d0#`5Uez@bb{Xn(BQLhScBhF!6+aIso0=l{PP7P(6-ru>nVy%AP z+|eZpY(ooMU7rtG$l#14v=Z?@ebOjm(A2)5k_${|wAA$oq+;42wiS78ezjgWWnTrF z`1!i2h{fM91aD8uxz?tZpE(PsL37e3$*I6%un5Bzzpn10p`j72R;3=Oaug_|Z(y)@ z9$SJN@-5d1tNIy0=7|d&_HAnDx!yDd-u#qmfuDh)0a_CVje{hvQz9rDFHJTpQ0Dg@ zGQ3t*gZlcFSXfx%OG@Cds&NDROxd^osY_)abmo^dKMUY!R~kGH%*;rutPF@Mx$zrv z6Q1soKnYYRW#;Bi-!H)>Br0<`y+Wy~p7_<>{ljuG`Dpje=v1x}-ND<)bWBr|<}v6B zkDTUZ^@VsH>CyR}ml4j2rB{}0q8eGwX>ExkI9yZN0)(P}$N(yi$AxmBY#Xj`(7zs{ zJbn2&jE`-*0lww_r;|fNaWm_xp;c9JHIv|RExZGKP%18qjgYa);`N-^VqXNVz{~)~ z?^&D;ouy!pKPy?%@xH`A zSR z7x%N3@o&{YEjfa|1;*eW_4TU{ zt;qCcY3Hj(<0DJuny*QL!y!StcG{>bhpUP%eVMq=1xcR>yZT8X9)1;rXOmQjPcANs zr>&Qb{rr66;s|4v3iGmQlMjr9j;G6pqNs%;TsyVNd3{i~hpDX8ugdcnd&UQJzj)rH zh>S6#n`cCJ9CwHv<2Ht$o`R5(h#r||VB?%J?s5W48;^o)b`Pi1^~}5{Y19lg{&W@LfHt*gc1`w$RfLrK{~H?A1$5 z;5v?AIhpN%gQsR6+Act9-3y z8>jCTMnWQq-^s3#Lb|WalgB$k3F>}lyCxs<2&A;LS0}s#<|hPx9kM#B+Lu2DiD_3P zelg;N!80(j@HNc2pXs}re%sHi+{aqBt~qUOy86?zN>7)yiCEJqy@2Gh#gzJE6j6Rx zBQK{77zW?gLWtQ20Dzntu16k9^N>DQ@Nmbx*mOg=F=k)8VJfM%y(Xu41;8YCz+@K| z9u7vhlT`BOnk_oMTeC;u@OhhoTeA`^34^iMihCLM_uVD>rI-9@4l7ocZl@DJ8FWZU zB0lRBIqkHj4#pE&mD(X!e!~;G$`7f47k* zOznM2@`&KM(|f5}sz)z%2}yJ5YmMj5Zwzr-W?v3R&@KuJ+l0zo==N@)nsbMHqHV}w z7#_ntMGCNM21RuH^SYG+RH0sHUsF2z7ams57@2xbPj0y5)8h+caqv@P^q!do+}>+X zzUBx|mikTawzXWYzJ4(AqAJpBF4ObmD_@gyg->oFGB6`k(8+?rFRV5P1yDkFM=8(c z%RI)iG(rKtq-^V%B_(R9;tk6WIzA?x@cESTXg zWYDBxkoNB5v6J8BP&n@HVtBNb@r+XYpjgub zR4oE*$ffXJuh2g8TCaLnpNoSxJ~Jx@ayx9z5Osa)=AI#bg^5eQb<6gpR%c+Qs#N*e z@XE4pAmjdI#0%pV7sIN>mNa^jTkd=<==2_#t-}9Ju&Z^|Lp$%B92@eN%=MRc)LK$% z@!XAg;dQ8bt=@ZNey7+a(dy^o;QKGP@Rb5NJYQRrGEC{J=FB(Irw-MAfoP(9RK;)&jlxSCT=W;ODCf($WqRFhqN#LR^qVhK zWhEp4`{Nnk;n0FHj}eNCZpRM`Y-@MIM&pvr7zQOZ3Ik5;CmZbR99b&22(!-07YNF) z$o0MKej-jnvQV39{TH4r2R5univa1{ASc|VOTi4c@`t2FId|xkh5typ-rdU;1j){adk@*+( zkHj{5B~eSy&HrPOOvl_FJ98)0V;^d`0-u0FTslgiLBQVGSTiSyu zgMGAu&R}SbNa-DgKJb?;fe3Qys$?=;5?V`eRiq*Kj$I`}Z*x4rC~eNM=DsOq(=nUW>(+7o@O8K-_U(X? zTyg032nXKax5W~SF5|eBj%r8Fa>i!ejC72*sd}zJ)t7Xy!gFvM`c4@*Iw>z$u)j_l zR-Uqxymg}>Ti>i%9j*4kwfC33i~kyIQ``n)r(L z!|H2*)Mwj4dk%e*L0tgFdW185>j4<7YwLXwcOsed`%6mS{+=&d@d!B}GkbDV*0 zNIWzW^|trz!&;qeI&mPiVDOUL70xpqVv0fpN9tjpu)@1LD9D<9}9{57j9!W$`zC6&i zl9lKkmPh`x)5+h>>JtiRNNBW5$_)%-)#+SVSGsjX2T=+SRX05>yJZd`1hyk<@{%1+ zDu^k>J$d*Qz6BZMwHx!@O**^Tx&fsHDw%$@J0nfj^je^Ihy*aIx{B(hkBvSvh46Z9 zRO)BjjXL_IHXKo~$4es=8Wxk;Y+&nVBCXA;=MVuLgVn8Mk(*y^+kP3f?Pr~4^A}hXj9UHS}qeI%XKD3KhHnkrNH0(Y20BWl&!Kfm`EVh2;i5C zpirU^K0nc2-I{cqvjZKVx z=&hH#-d=gDWjVE}cMNAPJf;#NYdQ=h`twjX6yquXuCNgGx1~uk{YHAmFpQF`ZLGC=~ukEyj?cFDI zH=@XvV#AY1EY4qb`y*;Ki>KuFB|2|toL7__Cr0S1Dl{s#y0=~7HSq~&7lpBc*VLua zvv3r&-LM*{hq%IYP7<@)dG-G$kMrZaqs(MYoZ zugEeJ@u(ip9rMoVtoFe;dF`^Br5x7v!rr5`hb5mJ#ocGqXHnm9m`yILjd0>UQSMv) z^v}l5^bM6RZ6M%{mkI) zHOoSp&dX)*xUt+kXscna#a`XxI;Ul2Sxa^i5sZc=(Q)oA^2-_;!pfYHAul+oA@Ilelm;rw@FYR+SIaWS?;_ zUdw<|qqaYq(nqu>rG48E9dYAoT6GH;QRuBYK1}W#C_Z_?7~k*pJ3?MzVt&rhZTsBy zw?nN$_Z>kimtwWcy`0?G#!)&7GjOcxCQps@p&ml8>~z(t=sjhR$6aFh!Vw5GA(lTh z5GM)jCwloa6a}7mdfqNYE7oi`Jv$m5>5qR%9eZ=)=a z+K4j5NpcDHHdepCS+P*{@o=yNp&TE(Sd4b0Notqso-Kt_mhDk1<-fa>T4KdY2N`U) zxu41vD%T&k$Gl?CW81%7r#-o1TZ0&PCcy}L4TPiV;sz`|S!&w8-s$rLdM zF&)>@`7=)65PWn#oi|8tXNb|((2ojf9d0fNZ^l7xY~dX~%*Xf-v2W-2n$i~s!4?H; z2qbQscFN21tqB{|x1+(^G~xQSrvX&Y;V-%?b1}zjBQX{GOFcVYTcwm>>}>6^HA=$x zn+z^Biv_5}0!#@7z1~YXJFCT2?D^jm+kH7jAqBo?M@ZdMl|2|66oLnSJXUOJtVLxe z0vH)N^t*qrjq=eFRMV>BFEfS)-2RzKlt973;d3D}4edwIE>kGc5-o=JV56ird)RlS z{Jg@0t-b#Ife80%!E~(7`qkZ8O~Q-8_{j7G&tqwX&&>^tm-#*{v7j-f1n0}mCR#7P z-4FkajD2$9?4Fc7-C_|0Z_G^bxIs%tWk|aFgSQ(qkM+5PRh=g&ZeAZg35$-kn~}_;~&fP-dCNCzg>{gyW!~LZpn?aZ~Va3~H0Ta)z z<4XPVk@;#%1S@fq<(2#8T04#8$mz>vM;(jek0>Qh!K%t5*4tU(fVYwD3Ri~=D!AmI zV$Dt#TEDX7{lpW%tF&DOlTO)vZodn_%wYu~)ZQ}Qo^cBbDHd{YajkzNxttQW>ST<^ z2~^xhB_y1sjIF5;xchvCn{QVugIE2eYZDZ!-Y-4lJdb34*k({@M zJ5!9Di^||~(IZ4iOoAbtggao+CaYvJynmB^;4r-tY2gS_*P!?U?hlEX;l+^*{%B2n z)|1j9wOHQQ^5Xha>{Cu8_w^8=#6;Dz7kU~RgTqn;ynDm6{xdlkf2vk0UK^oS3yVy4 zE+v&qnlYtPHBk#X&2}r7`@K`J@^e~Qm?iRJ*tbAaZDZTmB&mWMkZp7Kj7^kth#_uX z5z>gC(8Xz|Ie(+#&wiF3;Aey|Db(R*-U)!6;l_5@u?-$>j0SgEl5+c}Lfe-$p-dFH zB_$bC<)x6#A_2Uuo8=^l1@}vK!gvbF#b&MoH8ac3xMxUz$LFb8KU(x$YhtHanM_sw zYOFMBX2iNNSe&a}!;G9nv(tsW4@%3iQcqczOCF*JOBQ@4Orw=o?_vc(9$hfO`>U6& zyY_CUa9pASiJpmv`@oR!k;&$`h8!)$uS=}d-fPddfIdMDUW@%3y1LI(1Q=e$)sz(QC*E;Nfl99YTgk+|@jl`+iF?<_D?4YqV0Zl)lO8YWC@1ZWW^mi{5ePQN<~FQ2NMG$|K{py5akJa zkezmqhN)>MGMp$7=sOo2(7ppv``dCIwf&MaQQis7S596kkiw8Do(jO?EY4iJ4Hec6 z4Hymzu`w)cI9Pbq6GPtTP)x&Lmk;FT=ZCB4>(5}c0?;2l`p&?>&<;2(P8a3lOTNP# zdEzF5qDpkRR&PZC&cS{7xD@qV;(g5X%xI?m$9Q Date: Wed, 3 Dec 2025 14:07:36 +0100 Subject: [PATCH 36/50] [IMP] odoo_repository_migration: update README --- odoo_repository_migration/README.rst | 88 +++++++++-- .../readme/CONTRIBUTORS.md | 2 + .../readme/CONTRIBUTORS.rst | 2 - .../readme/DESCRIPTION.md | 27 ++++ .../readme/DESCRIPTION.rst | 1 - odoo_repository_migration/readme/USAGE.md | 10 ++ .../static/description/index.html | 137 ++++++++++++++---- 7 files changed, 221 insertions(+), 46 deletions(-) create mode 100644 odoo_repository_migration/readme/CONTRIBUTORS.md delete mode 100644 odoo_repository_migration/readme/CONTRIBUTORS.rst create mode 100644 odoo_repository_migration/readme/DESCRIPTION.md delete mode 100644 odoo_repository_migration/readme/DESCRIPTION.rst create mode 100644 odoo_repository_migration/readme/USAGE.md diff --git a/odoo_repository_migration/README.rst b/odoo_repository_migration/README.rst index 3f2df64a..146f7698 100644 --- a/odoo_repository_migration/README.rst +++ b/odoo_repository_migration/README.rst @@ -1,7 +1,3 @@ -.. image:: https://odoo-community.org/readme-banner-image - :target: https://odoo-community.org/get-involved?utm_source=readme - :alt: Odoo Community Association - ============================== Odoo Repository Migration Data ============================== @@ -17,7 +13,7 @@ Odoo Repository Migration Data .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status :alt: Beta -.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fodoo--repository-lightgray.png?logo=github @@ -32,13 +28,82 @@ Odoo Repository Migration Data |badge1| |badge2| |badge3| |badge4| |badge5| -This module collects modules migration data from Odoo repositories. +This module collects and records modules migration data from Odoo +repositories. + +Thanks to `oca-port `__ and data +collected by ``odoo_repository``, this module will generate migration +data on each module for declared migration paths (e.g. 16.0 -> 18.0). + +Also, for specific cases you can declare what a module became in a given +Odoo version, like OCA ``web_domain_field`` replaced by standard Odoo +module ``web`` starting from 17.0 (with an optional explanation that +could help users, like how to use this new module compared to the +previous one). + +Given a migration path, a module can get one of this migration status: + ++-----------------------------+---------------------------------------+ +| Status | Description | ++=============================+=======================================+ +| *Fully Ported* | All commits from source version are | +| | present in target version | ++-----------------------------+---------------------------------------+ +| *To migrate* | The module doesn't exist on target | +| | version | ++-----------------------------+---------------------------------------+ +| *Ported (missing commits?)* | Some commits from source version are | +| | not ported in target version (could | +| | be false-positive) | ++-----------------------------+---------------------------------------+ +| *To review* | A migration PR has been detected | ++-----------------------------+---------------------------------------+ +| *Replaced* | The module has been replaced by | +| | another one (not sharing the same git | +| | history) | ++-----------------------------+---------------------------------------+ +| *Moved to standard?* | The module name has been detected in | +| | Odoo standard repositories for target | +| | version. High chance this module is | +| | or should be replaced by another one | +| | instead (by creating a timeline), so | +| | it mainly helps to detect such cases. | ++-----------------------------+---------------------------------------+ +| *Moved to OCA* | the module name is available in an | +| | OCA repository (could be a | +| | false-positive because sharing the | +| | same name, in such case a timeline | +| | has to be created) | ++-----------------------------+---------------------------------------+ +| *Moved to generic repo* | a specific module (only available in | +| | a project) in source version now | +| | exists in a generic repository (could | +| | be a false-positive if both modules | +| | have only their name in common) | ++-----------------------------+---------------------------------------+ + +It helps to build a consolidated knowledge database accross different +Odoo versions for everyone: functionals and developers. **Table of contents** .. contents:: :local: +Usage +===== + +To enable this feature, the option *Collect migration data* should be +enabled on repositories (opt-in). + +To record what a module became starting from a given Odoo version, you +should do it through the *Odoo Repositories / Data / Modules / +Timelines* menu. + +Once the scheduled action ran, the migration data are available on each +module in *Migration* tab, or through the *Odoo Repositories / Data / +Modules / Migrations* menu. + Bug Tracker =========== @@ -53,18 +118,19 @@ Credits ======= Authors -~~~~~~~ +------- * Camptocamp Contributors -~~~~~~~~~~~~ +------------ -* Camptocamp - * Sébastien Alix +- Camptocamp + + - Sébastien Alix Maintainers -~~~~~~~~~~~ +----------- This module is maintained by the OCA. diff --git a/odoo_repository_migration/readme/CONTRIBUTORS.md b/odoo_repository_migration/readme/CONTRIBUTORS.md new file mode 100644 index 00000000..17752927 --- /dev/null +++ b/odoo_repository_migration/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +- Camptocamp + - Sébastien Alix \ diff --git a/odoo_repository_migration/readme/CONTRIBUTORS.rst b/odoo_repository_migration/readme/CONTRIBUTORS.rst deleted file mode 100644 index a0c91e35..00000000 --- a/odoo_repository_migration/readme/CONTRIBUTORS.rst +++ /dev/null @@ -1,2 +0,0 @@ -* Camptocamp - * Sébastien Alix diff --git a/odoo_repository_migration/readme/DESCRIPTION.md b/odoo_repository_migration/readme/DESCRIPTION.md new file mode 100644 index 00000000..6bd474cf --- /dev/null +++ b/odoo_repository_migration/readme/DESCRIPTION.md @@ -0,0 +1,27 @@ +This module collects and records modules migration data from Odoo +repositories. + +Thanks to [oca-port](https://github.com/OCA/oca-port/) and data +collected by `odoo_repository`, this module will generate migration data +on each module for declared migration paths (e.g. 16.0 -> 18.0). + +Also, for specific cases you can declare what a module became in a given +Odoo version, like OCA `web_domain_field` replaced by standard Odoo module +`web` starting from 17.0 (with an optional explanation that could help +users, like how to use this new module compared to the previous one). + +Given a migration path, a module can get one of this migration status: + +| Status | Description | +| ------ | ----------- | +| *Fully Ported* | All commits from source version are present in target version | +| *To migrate* | The module doesn't exist on target version | +| *Ported (missing commits?)* | Some commits from source version are not ported in target version (could be false-positive) | +| *To review* | A migration PR has been detected | +| *Replaced* | The module has been replaced by another one (not sharing the same git history) | +| *Moved to standard?* | The module name has been detected in Odoo standard repositories for target version. High chance this module is or should be replaced by another one instead (by creating a timeline), so it mainly helps to detect such cases. | +| *Moved to OCA* | the module name is available in an OCA repository (could be a false-positive because sharing the same name, in such case a timeline has to be created) | +| *Moved to generic repo* | a specific module (only available in a project) in source version now exists in a generic repository (could be a false-positive if both modules have only their name in common) | + +It helps to build a consolidated knowledge database accross different +Odoo versions for everyone: functionals and developers. diff --git a/odoo_repository_migration/readme/DESCRIPTION.rst b/odoo_repository_migration/readme/DESCRIPTION.rst deleted file mode 100644 index fa0b3fab..00000000 --- a/odoo_repository_migration/readme/DESCRIPTION.rst +++ /dev/null @@ -1 +0,0 @@ -This module collects modules migration data from Odoo repositories. diff --git a/odoo_repository_migration/readme/USAGE.md b/odoo_repository_migration/readme/USAGE.md new file mode 100644 index 00000000..daae5c2e --- /dev/null +++ b/odoo_repository_migration/readme/USAGE.md @@ -0,0 +1,10 @@ +To enable this feature, the option *Collect migration data* should be +enabled on repositories (opt-in). + +To record what a module became starting from a given Odoo version, you +should do it through the *Odoo Repositories / Data / Modules / +Timelines* menu. + +Once the scheduled action ran, the migration data are available on each +module in *Migration* tab, or through the *Odoo Repositories / Data / +Modules / Migrations* menu. diff --git a/odoo_repository_migration/static/description/index.html b/odoo_repository_migration/static/description/index.html index 6ba7c13c..ed2c3dfb 100644 --- a/odoo_repository_migration/static/description/index.html +++ b/odoo_repository_migration/static/description/index.html @@ -2,19 +2,18 @@ - -README.rst + +Odoo Repository Migration Data -
+
+

Odoo Repository Migration Data

- - -Odoo Community Association - -
-

Odoo Repository Migration Data

-

Beta License: AGPL-3 OCA/odoo-repository Translate me on Weblate Try me on Runboat

-

This module collects modules migration data from Odoo repositories.

+

Beta License: AGPL-3 OCA/odoo-repository Translate me on Weblate Try me on Runboat

+

This module collects and records modules migration data from Odoo +repositories.

+

Thanks to oca-port and data +collected by odoo_repository, this module will generate migration +data on each module for declared migration paths (e.g. 16.0 -> 18.0).

+

Also, for specific cases you can declare what a module became in a given +Odoo version, like OCA web_domain_field replaced by standard Odoo +module web starting from 17.0 (with an optional explanation that +could help users, like how to use this new module compared to the +previous one).

+

Given a migration path, a module can get one of this migration status:

+ ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StatusDescription
Fully PortedAll commits from source version are +present in target version
To migrateThe module doesn’t exist on target +version
Ported (missing commits?)Some commits from source version are +not ported in target version (could +be false-positive)
To reviewA migration PR has been detected
ReplacedThe module has been replaced by +another one (not sharing the same git +history)
Moved to standard?The module name has been detected in +Odoo standard repositories for target +version. High chance this module is +or should be replaced by another one +instead (by creating a timeline), so +it mainly helps to detect such cases.
Moved to OCAthe module name is available in an +OCA repository (could be a +false-positive because sharing the +same name, in such case a timeline +has to be created)
Moved to generic repoa specific module (only available in +a project) in source version now +exists in a generic repository (could +be a false-positive if both modules +have only their name in common)
+

It helps to build a consolidated knowledge database accross different +Odoo versions for everyone: functionals and developers.

Table of contents

+
+

Usage

+

To enable this feature, the option Collect migration data should be +enabled on repositories (opt-in).

+

To record what a module became starting from a given Odoo version, you +should do it through the Odoo Repositories / Data / Modules / +Timelines menu.

+

Once the scheduled action ran, the migration data are available on each +module in Migration tab, or through the Odoo Repositories / Data / +Modules / Migrations menu.

+
-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed @@ -397,26 +471,26 @@

Bug Tracker

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • Camptocamp
-

Contributors

+

Contributors

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

- -Odoo Community Association - +Odoo Community Association

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

@@ -425,6 +499,5 @@

Maintainers

-
From 877334f233f4ecee7f399f11898cd2ed016ba1bd Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Mon, 8 Dec 2025 11:19:19 +0000 Subject: [PATCH 37/50] [UPD] README.rst --- odoo_repository_migration/README.rst | 83 +++++++++--------- .../static/description/index.html | 86 ++++++++++--------- 2 files changed, 90 insertions(+), 79 deletions(-) diff --git a/odoo_repository_migration/README.rst b/odoo_repository_migration/README.rst index 146f7698..4adf3cfb 100644 --- a/odoo_repository_migration/README.rst +++ b/odoo_repository_migration/README.rst @@ -1,3 +1,7 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + ============================== Odoo Repository Migration Data ============================== @@ -7,13 +11,13 @@ Odoo Repository Migration Data !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:ca1a8de995fd9b4e82e491087c7f380a6a17ae31d175e8709f2ddb43fd9f95cb + !! source digest: sha256:0fbac9f1a41dc3b98caa116fb5f5b775aeedd201e7a99c8f8aebae5c9bdaef84 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status :alt: Beta -.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png +.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fodoo--repository-lightgray.png?logo=github @@ -43,44 +47,43 @@ previous one). Given a migration path, a module can get one of this migration status: -+-----------------------------+---------------------------------------+ -| Status | Description | -+=============================+=======================================+ -| *Fully Ported* | All commits from source version are | -| | present in target version | -+-----------------------------+---------------------------------------+ -| *To migrate* | The module doesn't exist on target | -| | version | -+-----------------------------+---------------------------------------+ -| *Ported (missing commits?)* | Some commits from source version are | -| | not ported in target version (could | -| | be false-positive) | -+-----------------------------+---------------------------------------+ -| *To review* | A migration PR has been detected | -+-----------------------------+---------------------------------------+ -| *Replaced* | The module has been replaced by | -| | another one (not sharing the same git | -| | history) | -+-----------------------------+---------------------------------------+ -| *Moved to standard?* | The module name has been detected in | -| | Odoo standard repositories for target | -| | version. High chance this module is | -| | or should be replaced by another one | -| | instead (by creating a timeline), so | -| | it mainly helps to detect such cases. | -+-----------------------------+---------------------------------------+ -| *Moved to OCA* | the module name is available in an | -| | OCA repository (could be a | -| | false-positive because sharing the | -| | same name, in such case a timeline | -| | has to be created) | -+-----------------------------+---------------------------------------+ -| *Moved to generic repo* | a specific module (only available in | -| | a project) in source version now | -| | exists in a generic repository (could | -| | be a false-positive if both modules | -| | have only their name in common) | -+-----------------------------+---------------------------------------+ ++-----------------------------+----------------------------------------+ +| Status | Description | ++=============================+========================================+ +| *Fully Ported* | All commits from source version are | +| | present in target version | ++-----------------------------+----------------------------------------+ +| *To migrate* | The module doesn't exist on target | +| | version | ++-----------------------------+----------------------------------------+ +| *Ported (missing commits?)* | Some commits from source version are | +| | not ported in target version (could be | +| | false-positive) | ++-----------------------------+----------------------------------------+ +| *To review* | A migration PR has been detected | ++-----------------------------+----------------------------------------+ +| *Replaced* | The module has been replaced by | +| | another one (not sharing the same git | +| | history) | ++-----------------------------+----------------------------------------+ +| *Moved to standard?* | The module name has been detected in | +| | Odoo standard repositories for target | +| | version. High chance this module is or | +| | should be replaced by another one | +| | instead (by creating a timeline), so | +| | it mainly helps to detect such cases. | ++-----------------------------+----------------------------------------+ +| *Moved to OCA* | the module name is available in an OCA | +| | repository (could be a false-positive | +| | because sharing the same name, in such | +| | case a timeline has to be created) | ++-----------------------------+----------------------------------------+ +| *Moved to generic repo* | a specific module (only available in a | +| | project) in source version now exists | +| | in a generic repository (could be a | +| | false-positive if both modules have | +| | only their name in common) | ++-----------------------------+----------------------------------------+ It helps to build a consolidated knowledge database accross different Odoo versions for everyone: functionals and developers. diff --git a/odoo_repository_migration/static/description/index.html b/odoo_repository_migration/static/description/index.html index ed2c3dfb..4bd319e5 100644 --- a/odoo_repository_migration/static/description/index.html +++ b/odoo_repository_migration/static/description/index.html @@ -2,18 +2,19 @@ - -Odoo Repository Migration Data + +README.rst -
-

Odoo Repository Migration Data

+
+ + +Odoo Community Association + +
+

Odoo Repository Migration Data

-

Beta License: AGPL-3 OCA/odoo-repository Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/odoo-repository Translate me on Weblate Try me on Runboat

This module collects and records modules migration data from Odoo repositories.

Thanks to oca-port and data @@ -382,8 +388,8 @@

Odoo Repository Migration Data

Given a migration path, a module can get one of this migration status:

--++ @@ -401,8 +407,8 @@

Odoo Repository Migration Data

+not ported in target version (could be +false-positive) @@ -415,24 +421,23 @@

Odoo Repository Migration Data

- + - +
Status
Ported (missing commits?) Some commits from source version are -not ported in target version (could -be false-positive)
To review A migration PR has been detected
Moved to standard? The module name has been detected in Odoo standard repositories for target -version. High chance this module is -or should be replaced by another one +version. High chance this module is or +should be replaced by another one instead (by creating a timeline), so it mainly helps to detect such cases.
Moved to OCAthe module name is available in an -OCA repository (could be a -false-positive because sharing the -same name, in such case a timeline -has to be created)the module name is available in an OCA +repository (could be a false-positive +because sharing the same name, in such +case a timeline has to be created)
Moved to generic repoa specific module (only available in -a project) in source version now -exists in a generic repository (could -be a false-positive if both modules -have only their name in common)a specific module (only available in a +project) in source version now exists +in a generic repository (could be a +false-positive if both modules have +only their name in common)
@@ -441,18 +446,18 @@

Odoo Repository Migration Data

Table of contents

-

Usage

+

Usage

To enable this feature, the option Collect migration data should be enabled on repositories (opt-in).

To record what a module became starting from a given Odoo version, you @@ -463,7 +468,7 @@

Usage

Modules / Migrations menu.

-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed @@ -471,15 +476,15 @@

Bug Tracker

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • Camptocamp
-

Contributors

+

Contributors

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

-Odoo Community Association + +Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

@@ -499,5 +506,6 @@

Maintainers

+
From d82b36e3ef65358962e53512568c175a6133470e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Thu, 18 Dec 2025 10:01:24 +0100 Subject: [PATCH 38/50] [FIX] odoo_repository_migration: fix module scanning when it is replaced Bugfix following-up commit 39e6bd21026d28aacdb8bd3d11f3c217b73271cd. --- odoo_repository_migration/models/odoo_repository.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py index b3a23203..dcf6f907 100644 --- a/odoo_repository_migration/models/odoo_repository.py +++ b/odoo_repository_migration/models/odoo_repository.py @@ -186,12 +186,13 @@ def _scan_migration_module( self.env["odoo.migration.path"].browse(migration_path_id).exists() ) # Skip migration scan if module is replaced in next versions - if module._replaced_by_module_in_target_version( + replaced_by_module = module._replaced_by_module_in_target_version( migration_path.target_branch_id - ): + ) + if replaced_by_module: return ( f"{module.name} is now replaced by " - f"{module.next_odoo_version_module_id.name}, no need to collect " + f"{replaced_by_module.name}, no need to collect " "migration data." ) # Check if module has already been migrated on target version but in a From 595b2dee7eef596c3258237850b31c50439c35c1 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 18 Dec 2025 09:19:36 +0000 Subject: [PATCH 39/50] [BOT] post-merge updates --- odoo_repository_migration/README.rst | 18 +++++++++--------- odoo_repository_migration/__manifest__.py | 2 +- .../static/description/index.html | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/odoo_repository_migration/README.rst b/odoo_repository_migration/README.rst index 4adf3cfb..312b59aa 100644 --- a/odoo_repository_migration/README.rst +++ b/odoo_repository_migration/README.rst @@ -11,7 +11,7 @@ Odoo Repository Migration Data !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:0fbac9f1a41dc3b98caa116fb5f5b775aeedd201e7a99c8f8aebae5c9bdaef84 + !! source digest: sha256:ae395cc60d699192b6cf738dc35db88f7eff53c3647a78e2351c179128320aa5 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png @@ -20,14 +20,14 @@ Odoo Repository Migration Data .. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 -.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fodoo--repository-lightgray.png?logo=github - :target: https://github.com/OCA/odoo-repository/tree/16.0/odoo_repository_migration - :alt: OCA/odoo-repository +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fmodule--composition--analysis-lightgray.png?logo=github + :target: https://github.com/OCA/module-composition-analysis/tree/16.0/odoo_repository_migration + :alt: OCA/module-composition-analysis .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/odoo-repository-16-0/odoo-repository-16-0-odoo_repository_migration + :target: https://translation.odoo-community.org/projects/module-composition-analysis-16-0/module-composition-analysis-16-0-odoo_repository_migration :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/odoo-repository&target_branch=16.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/module-composition-analysis&target_branch=16.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -110,10 +110,10 @@ Modules / Migrations* menu. Bug Tracker =========== -Bugs are tracked on `GitHub Issues `_. +Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -145,6 +145,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -This module is part of the `OCA/odoo-repository `_ project on GitHub. +This module is part of the `OCA/module-composition-analysis `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/odoo_repository_migration/__manifest__.py b/odoo_repository_migration/__manifest__.py index 26385d82..3963cc85 100644 --- a/odoo_repository_migration/__manifest__.py +++ b/odoo_repository_migration/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Odoo Repository Migration Data", "summary": "Collect modules migration data for Odoo Repositories.", - "version": "16.0.1.3.0", + "version": "16.0.1.3.1", "category": "Tools", "author": "Camptocamp, Odoo Community Association (OCA)", "website": "https://github.com/camptocamp/odoo-repository", diff --git a/odoo_repository_migration/static/description/index.html b/odoo_repository_migration/static/description/index.html index 4bd319e5..451a3745 100644 --- a/odoo_repository_migration/static/description/index.html +++ b/odoo_repository_migration/static/description/index.html @@ -372,9 +372,9 @@

Odoo Repository Migration Data

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:0fbac9f1a41dc3b98caa116fb5f5b775aeedd201e7a99c8f8aebae5c9bdaef84 +!! source digest: sha256:ae395cc60d699192b6cf738dc35db88f7eff53c3647a78e2351c179128320aa5 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/odoo-repository Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/module-composition-analysis Translate me on Weblate Try me on Runboat

This module collects and records modules migration data from Odoo repositories.

Thanks to oca-port and data @@ -469,10 +469,10 @@

Usage

Bug Tracker

-

Bugs are tracked on GitHub Issues. +

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

@@ -501,7 +501,7 @@

Maintainers

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

-

This module is part of the OCA/odoo-repository project on GitHub.

+

This module is part of the OCA/module-composition-analysis project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

From 28a4c7f5ab87115a976d65978f0be4b403c2bc1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Sat, 17 Jan 2026 13:16:12 +0100 Subject: [PATCH 40/50] Update all modules manifest and README with new repo info --- odoo_repository_migration/README.rst | 2 +- odoo_repository_migration/__manifest__.py | 2 +- odoo_repository_migration/static/description/index.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/odoo_repository_migration/README.rst b/odoo_repository_migration/README.rst index 312b59aa..dc92ea43 100644 --- a/odoo_repository_migration/README.rst +++ b/odoo_repository_migration/README.rst @@ -11,7 +11,7 @@ Odoo Repository Migration Data !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:ae395cc60d699192b6cf738dc35db88f7eff53c3647a78e2351c179128320aa5 + !! source digest: sha256:99462624428f4cf892ad96b5d989adf5014ec700b8668f653e14869d7f18dd66 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/odoo_repository_migration/__manifest__.py b/odoo_repository_migration/__manifest__.py index 3963cc85..61b1b28c 100644 --- a/odoo_repository_migration/__manifest__.py +++ b/odoo_repository_migration/__manifest__.py @@ -6,7 +6,7 @@ "version": "16.0.1.3.1", "category": "Tools", "author": "Camptocamp, Odoo Community Association (OCA)", - "website": "https://github.com/camptocamp/odoo-repository", + "website": "https://github.com/OCA/module-composition-analysis", "data": [ "security/ir.model.access.csv", "data/queue_job.xml", diff --git a/odoo_repository_migration/static/description/index.html b/odoo_repository_migration/static/description/index.html index 451a3745..a23e78c6 100644 --- a/odoo_repository_migration/static/description/index.html +++ b/odoo_repository_migration/static/description/index.html @@ -372,7 +372,7 @@

Odoo Repository Migration Data

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:ae395cc60d699192b6cf738dc35db88f7eff53c3647a78e2351c179128320aa5 +!! source digest: sha256:99462624428f4cf892ad96b5d989adf5014ec700b8668f653e14869d7f18dd66 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/module-composition-analysis Translate me on Weblate Try me on Runboat

This module collects and records modules migration data from Odoo From c584126a1345b217ffff9e2c9698c23cb23d6df8 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Sat, 17 Jan 2026 12:45:07 +0000 Subject: [PATCH 41/50] [BOT] post-merge updates --- odoo_repository_migration/README.rst | 2 +- odoo_repository_migration/__manifest__.py | 2 +- odoo_repository_migration/static/description/index.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/odoo_repository_migration/README.rst b/odoo_repository_migration/README.rst index dc92ea43..d643be3a 100644 --- a/odoo_repository_migration/README.rst +++ b/odoo_repository_migration/README.rst @@ -11,7 +11,7 @@ Odoo Repository Migration Data !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:99462624428f4cf892ad96b5d989adf5014ec700b8668f653e14869d7f18dd66 + !! source digest: sha256:897a7456693242289caa6a0ae4c8e32ea2c2d336832aa6ef5a4e50262e2865e6 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/odoo_repository_migration/__manifest__.py b/odoo_repository_migration/__manifest__.py index 61b1b28c..1fbde63e 100644 --- a/odoo_repository_migration/__manifest__.py +++ b/odoo_repository_migration/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Odoo Repository Migration Data", "summary": "Collect modules migration data for Odoo Repositories.", - "version": "16.0.1.3.1", + "version": "16.0.1.3.2", "category": "Tools", "author": "Camptocamp, Odoo Community Association (OCA)", "website": "https://github.com/OCA/module-composition-analysis", diff --git a/odoo_repository_migration/static/description/index.html b/odoo_repository_migration/static/description/index.html index a23e78c6..b7f783c6 100644 --- a/odoo_repository_migration/static/description/index.html +++ b/odoo_repository_migration/static/description/index.html @@ -372,7 +372,7 @@

Odoo Repository Migration Data

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:99462624428f4cf892ad96b5d989adf5014ec700b8668f653e14869d7f18dd66 +!! source digest: sha256:897a7456693242289caa6a0ae4c8e32ea2c2d336832aa6ef5a4e50262e2865e6 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/module-composition-analysis Translate me on Weblate Try me on Runboat

This module collects and records modules migration data from Odoo From 87c484b2421120c69de0ffa51a45d782157643ab Mon Sep 17 00:00:00 2001 From: oca-ci Date: Sun, 1 Feb 2026 10:53:27 +0000 Subject: [PATCH 42/50] [UPD] Update odoo_repository_migration.pot --- .../i18n/odoo_repository_migration.pot | 483 ++++++++++++++++++ 1 file changed, 483 insertions(+) create mode 100644 odoo_repository_migration/i18n/odoo_repository_migration.pot diff --git a/odoo_repository_migration/i18n/odoo_repository_migration.pot b/odoo_repository_migration/i18n/odoo_repository_migration.pot new file mode 100644 index 00000000..4a8547ad --- /dev/null +++ b/odoo_repository_migration/i18n/odoo_repository_migration.pot @@ -0,0 +1,483 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * odoo_repository_migration +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_view_form +msgid "Next Versions" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__active +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__active +msgid "Active" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__author_ids +msgid "Authors" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_repository__collect_migration_data +msgid "Collect migration data" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,help:odoo_repository_migration.field_odoo_repository__collect_migration_data +msgid "Collect migration data based on the configured migration paths." +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_view_search +msgid "Commits to Port" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__create_uid +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__create_uid +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__create_uid +msgid "Created by" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__create_date +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__create_date +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__create_date +msgid "Created on" +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_form +msgid "Data" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model,name:odoo_repository_migration.model_odoo_migration_path +msgid "Define a migration path (from one branch to another)" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__display_name +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__display_name +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__display_name +msgid "Display Name" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_migration__state__fully_ported +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +msgid "Fully Ported" +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_timeline_view_search +msgid "Group By" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__id +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__id +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__id +msgid "ID" +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_form +msgid "Info" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path____last_update +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration____last_update +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline____last_update +msgid "Last Modified on" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__last_source_scanned_commit +msgid "Last Source Scanned Commit" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__last_target_scanned_commit +msgid "Last Target Scanned Commit" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__write_uid +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__write_uid +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__write_date +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__write_date +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__write_date +msgid "Last Updated on" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__maintainer_ids +msgid "Maintainers" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__migration_path_id +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +msgid "Migration Path" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.actions.act_window,name:odoo_repository_migration.odoo_migration_path_action +#: model:ir.ui.menu,name:odoo_repository_migration.odoo_migration_path_menu +msgid "Migration Paths" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch__migration_scan +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__migration_scan +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_project_module__migration_scan +msgid "Migration Scan" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__state +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +msgid "Migration Status" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model,name:odoo_repository_migration.model_odoo_module_branch_migration +msgid "Migration data for a module of a given branch." +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +msgid "Migration to review" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.actions.act_window,name:odoo_repository_migration.odoo_module_branch_migration_action +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch__migration_ids +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_project_module__migration_ids +#: model:ir.ui.menu,name:odoo_repository_migration.odoo_module_branch_migration_menu +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_view_form +msgid "Migrations" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__module_branch_id +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +msgid "Module" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,help:odoo_repository_migration.field_odoo_module_branch_migration__moved_to_oca +msgid "" +"Module now available in OCA. This module is maybe not exactly the same, and " +"doesn't have the same scope so it deserves a check during a migration." +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,help:odoo_repository_migration.field_odoo_module_branch_migration__moved_to_standard +msgid "" +"Module now available in Odoo standard code. This module is maybe not exactly" +" the same, and doesn't have the same scope so it deserves a check during a " +"migration." +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__moved_to_oca +msgid "Moved To Oca" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__moved_to_standard +msgid "Moved To Standard" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_migration__state__moved_to_oca +msgid "Moved to OCA" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_migration__state__moved_to_generic +msgid "Moved to generic repo" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_migration__state__moved_to_standard +msgid "Moved to standard?" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__name +msgid "Name" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__next_module_branch_id +msgid "New module" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__next_module_id +msgid "New module name" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch__next_odoo_version_module_branch_id +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_project_module__next_odoo_version_module_branch_id +msgid "Next Odoo Version Module Branch" +msgstr "" + +#. module: odoo_repository_migration +#. odoo-python +#: code:addons/odoo_repository_migration/models/odoo_module_branch.py:0 +#, python-format +msgid "Next versions" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__note +msgid "Note" +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_timeline_view_form +msgid "Notes" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__moved_to_generic +msgid "Now generic" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model,name:odoo_repository_migration.model_odoo_module_branch +msgid "Odoo Module Branch" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model,name:odoo_repository_migration.model_odoo_module_branch_timeline +msgid "Odoo Module Timeline (renaming/replacement)" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model,name:odoo_repository_migration.model_odoo_repository +msgid "Odoo Modules Repository" +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_timeline_view_search +msgid "Odoo Version" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__org_id +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__org_id +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_timeline_view_search +msgid "Organization" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__pr_url +msgid "PR URL" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_migration__state__port_commits +msgid "Ported (missing commits?)" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__process +msgid "Process" +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_timeline_view_search +msgid "Renamed" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__renamed_to_module_id +msgid "Renamed to" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,help:odoo_repository_migration.field_odoo_module_branch_timeline__state +msgid "" +"Renamed: modules still share the same Git history (it allows to check commits that could be ported)\n" +"Replaced: module has been replaced (or merged) by another one that fulfill the same feature" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_migration__state__replaced +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_timeline_view_search +msgid "Replaced" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__replaced_by_module_id +msgid "Replaced by" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__repository_id +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__repository_id +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_timeline_view_search +msgid "Repository" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__results +msgid "Results" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__results_text +msgid "Results Text" +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_migration_path_view_form +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_form +msgid "Scan" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__odoo_version_sequence +msgid "Sequence" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__module_branch_id +msgid "Source" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__source_branch_id +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__source_branch_id +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +msgid "Source Branch" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,help:odoo_repository_migration.field_odoo_module_branch_migration__moved_to_generic +msgid "" +"Specific module now available in a generic repository. This module is maybe " +"not exactly the same, and doesn't have the same scope so it deserves a check" +" during a migration." +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__odoo_version_id +msgid "Starting from version" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__state +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_timeline_view_search +msgid "State" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__target_module_branch_id +msgid "Target" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__target_branch_id +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__target_branch_id +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +msgid "Target Branch" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,help:odoo_repository_migration.field_odoo_module_branch_migration__migration_scan +msgid "Technical field telling if this migration path needs a migration scan." +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,help:odoo_repository_migration.field_odoo_module_branch__migration_scan +#: model:ir.model.fields,help:odoo_repository_migration.field_odoo_project_module__migration_scan +msgid "" +"Technical field telling if this module is elligible for a migration scan." +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__module_id +msgid "Technical name" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.constraint,message:odoo_repository_migration.constraint_odoo_migration_path_migration_path_uniq +msgid "This migration path already exists." +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.constraint,message:odoo_repository_migration.constraint_odoo_module_branch_migration_module_migration_path_uniq +msgid "This module migration path already exists." +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_migration_path_view_form +msgid "This operation will scan all relevant repositories. Are you sure?" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch__timeline_ids +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_project_module__timeline_ids +msgid "Timeline" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.actions.act_window,name:odoo_repository_migration.odoo_module_branch_timeline_action +#: model:ir.ui.menu,name:odoo_repository_migration.odoo_module_branch_timeline_menu +msgid "Timelines" +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_view_search +msgid "To Migrate" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_migration__state__migrate +msgid "To migrate" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_migration__state__review_migration +msgid "To review" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_timeline__state__renamed +msgid "has been renamed to" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_timeline__state__replaced +msgid "has been replaced by" +msgstr "" From fedce39151ed7f1ed56da87dbd377bec24a0fc9d Mon Sep 17 00:00:00 2001 From: mymage Date: Mon, 2 Feb 2026 07:58:12 +0000 Subject: [PATCH 43/50] Added translation using Weblate (Italian) --- odoo_repository_migration/i18n/it.po | 484 +++++++++++++++++++++++++++ 1 file changed, 484 insertions(+) create mode 100644 odoo_repository_migration/i18n/it.po diff --git a/odoo_repository_migration/i18n/it.po b/odoo_repository_migration/i18n/it.po new file mode 100644 index 00000000..51d8784d --- /dev/null +++ b/odoo_repository_migration/i18n/it.po @@ -0,0 +1,484 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * odoo_repository_migration +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_view_form +msgid "Next Versions" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__active +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__active +msgid "Active" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__author_ids +msgid "Authors" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_repository__collect_migration_data +msgid "Collect migration data" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,help:odoo_repository_migration.field_odoo_repository__collect_migration_data +msgid "Collect migration data based on the configured migration paths." +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_view_search +msgid "Commits to Port" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__create_uid +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__create_uid +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__create_uid +msgid "Created by" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__create_date +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__create_date +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__create_date +msgid "Created on" +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_form +msgid "Data" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model,name:odoo_repository_migration.model_odoo_migration_path +msgid "Define a migration path (from one branch to another)" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__display_name +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__display_name +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__display_name +msgid "Display Name" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_migration__state__fully_ported +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +msgid "Fully Ported" +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_timeline_view_search +msgid "Group By" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__id +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__id +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__id +msgid "ID" +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_form +msgid "Info" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path____last_update +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration____last_update +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline____last_update +msgid "Last Modified on" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__last_source_scanned_commit +msgid "Last Source Scanned Commit" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__last_target_scanned_commit +msgid "Last Target Scanned Commit" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__write_uid +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__write_uid +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__write_date +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__write_date +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__write_date +msgid "Last Updated on" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__maintainer_ids +msgid "Maintainers" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__migration_path_id +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +msgid "Migration Path" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.actions.act_window,name:odoo_repository_migration.odoo_migration_path_action +#: model:ir.ui.menu,name:odoo_repository_migration.odoo_migration_path_menu +msgid "Migration Paths" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch__migration_scan +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__migration_scan +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_project_module__migration_scan +msgid "Migration Scan" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__state +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +msgid "Migration Status" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model,name:odoo_repository_migration.model_odoo_module_branch_migration +msgid "Migration data for a module of a given branch." +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +msgid "Migration to review" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.actions.act_window,name:odoo_repository_migration.odoo_module_branch_migration_action +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch__migration_ids +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_project_module__migration_ids +#: model:ir.ui.menu,name:odoo_repository_migration.odoo_module_branch_migration_menu +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_view_form +msgid "Migrations" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__module_branch_id +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +msgid "Module" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,help:odoo_repository_migration.field_odoo_module_branch_migration__moved_to_oca +msgid "" +"Module now available in OCA. This module is maybe not exactly the same, and " +"doesn't have the same scope so it deserves a check during a migration." +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,help:odoo_repository_migration.field_odoo_module_branch_migration__moved_to_standard +msgid "" +"Module now available in Odoo standard code. This module is maybe not exactly" +" the same, and doesn't have the same scope so it deserves a check during a " +"migration." +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__moved_to_oca +msgid "Moved To Oca" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__moved_to_standard +msgid "Moved To Standard" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_migration__state__moved_to_oca +msgid "Moved to OCA" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_migration__state__moved_to_generic +msgid "Moved to generic repo" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_migration__state__moved_to_standard +msgid "Moved to standard?" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__name +msgid "Name" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__next_module_branch_id +msgid "New module" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__next_module_id +msgid "New module name" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch__next_odoo_version_module_branch_id +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_project_module__next_odoo_version_module_branch_id +msgid "Next Odoo Version Module Branch" +msgstr "" + +#. module: odoo_repository_migration +#. odoo-python +#: code:addons/odoo_repository_migration/models/odoo_module_branch.py:0 +#, python-format +msgid "Next versions" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__note +msgid "Note" +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_timeline_view_form +msgid "Notes" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__moved_to_generic +msgid "Now generic" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model,name:odoo_repository_migration.model_odoo_module_branch +msgid "Odoo Module Branch" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model,name:odoo_repository_migration.model_odoo_module_branch_timeline +msgid "Odoo Module Timeline (renaming/replacement)" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model,name:odoo_repository_migration.model_odoo_repository +msgid "Odoo Modules Repository" +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_timeline_view_search +msgid "Odoo Version" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__org_id +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__org_id +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_timeline_view_search +msgid "Organization" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__pr_url +msgid "PR URL" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_migration__state__port_commits +msgid "Ported (missing commits?)" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__process +msgid "Process" +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_timeline_view_search +msgid "Renamed" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__renamed_to_module_id +msgid "Renamed to" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,help:odoo_repository_migration.field_odoo_module_branch_timeline__state +msgid "" +"Renamed: modules still share the same Git history (it allows to check commits that could be ported)\n" +"Replaced: module has been replaced (or merged) by another one that fulfill the same feature" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_migration__state__replaced +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_timeline_view_search +msgid "Replaced" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__replaced_by_module_id +msgid "Replaced by" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__repository_id +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__repository_id +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_timeline_view_search +msgid "Repository" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__results +msgid "Results" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__results_text +msgid "Results Text" +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_migration_path_view_form +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_form +msgid "Scan" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__odoo_version_sequence +msgid "Sequence" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__module_branch_id +msgid "Source" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__source_branch_id +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__source_branch_id +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +msgid "Source Branch" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,help:odoo_repository_migration.field_odoo_module_branch_migration__moved_to_generic +msgid "" +"Specific module now available in a generic repository. This module is maybe " +"not exactly the same, and doesn't have the same scope so it deserves a check" +" during a migration." +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__odoo_version_id +msgid "Starting from version" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_timeline__state +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_timeline_view_search +msgid "State" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__target_module_branch_id +msgid "Target" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_migration_path__target_branch_id +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__target_branch_id +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +msgid "Target Branch" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,help:odoo_repository_migration.field_odoo_module_branch_migration__migration_scan +msgid "Technical field telling if this migration path needs a migration scan." +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,help:odoo_repository_migration.field_odoo_module_branch__migration_scan +#: model:ir.model.fields,help:odoo_repository_migration.field_odoo_project_module__migration_scan +msgid "" +"Technical field telling if this module is elligible for a migration scan." +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch_migration__module_id +msgid "Technical name" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.constraint,message:odoo_repository_migration.constraint_odoo_migration_path_migration_path_uniq +msgid "This migration path already exists." +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.constraint,message:odoo_repository_migration.constraint_odoo_module_branch_migration_module_migration_path_uniq +msgid "This module migration path already exists." +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_migration_path_view_form +msgid "This operation will scan all relevant repositories. Are you sure?" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_module_branch__timeline_ids +#: model:ir.model.fields,field_description:odoo_repository_migration.field_odoo_project_module__timeline_ids +msgid "Timeline" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.actions.act_window,name:odoo_repository_migration.odoo_module_branch_timeline_action +#: model:ir.ui.menu,name:odoo_repository_migration.odoo_module_branch_timeline_menu +msgid "Timelines" +msgstr "" + +#. module: odoo_repository_migration +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_migration_view_search +#: model_terms:ir.ui.view,arch_db:odoo_repository_migration.odoo_module_branch_view_search +msgid "To Migrate" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_migration__state__migrate +msgid "To migrate" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_migration__state__review_migration +msgid "To review" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_timeline__state__renamed +msgid "has been renamed to" +msgstr "" + +#. module: odoo_repository_migration +#: model:ir.model.fields.selection,name:odoo_repository_migration.selection__odoo_module_branch_timeline__state__replaced +msgid "has been replaced by" +msgstr "" From d621f061d2c19991d686e3c45ed2182422f6aa39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Mon, 16 Feb 2026 08:54:28 +0100 Subject: [PATCH 44/50] [FIX] odoo_repository_migration: fix tests OCA repositories do not have external IDs anymore. --- .../tests/test_odoo_module_branch.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/odoo_repository_migration/tests/test_odoo_module_branch.py b/odoo_repository_migration/tests/test_odoo_module_branch.py index b5b38356..8da7cc45 100644 --- a/odoo_repository_migration/tests/test_odoo_module_branch.py +++ b/odoo_repository_migration/tests/test_odoo_module_branch.py @@ -1,4 +1,5 @@ # Copyright 2024 Camptocamp SA +# Copyright 2026 Sébastien Alix # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) from odoo.addons.odoo_repository.tests import common @@ -22,7 +23,14 @@ def setUp(self): last_scanned_commit="sha", ) self.std_repository = self.env.ref("odoo_repository.odoo_repository_odoo_odoo") - self.oca_repository = self.env.ref("odoo_repository.repo_oca_server_tools") + oca_org = self.env.ref("odoo_repository.odoo_repository_org_oca") + self.oca_repository = self.env["odoo.repository"].create( + { + "org_id": oca_org.id, + "name": "test-repo", + "repo_url": "https://github.com/OCA/test-repo", + } + ) self.gen_repository = self.env["odoo.repository"].create( { "name": "new_repo", From 2980fcaba5deea0ab34c9eaec776c454f019a747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Fri, 27 Mar 2026 09:36:21 +0100 Subject: [PATCH 45/50] [FIX] odoo_repository_migration: explicit commits are not allowed in queue jobs --- odoo_repository_migration/utils/scanner.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/odoo_repository_migration/utils/scanner.py b/odoo_repository_migration/utils/scanner.py index a5734fcc..18f01796 100644 --- a/odoo_repository_migration/utils/scanner.py +++ b/odoo_repository_migration/utils/scanner.py @@ -95,6 +95,4 @@ def _push_scanned_data(self, module_branch_id: int, data: dict): res = self.env["odoo.module.branch.migration"].push_scanned_data( module_branch_id, data ) - # Commit after each scan - self.env.cr.commit() # pylint: disable=invalid-commit return res From 86b9e27af2eed466a4458807facf95714eeb2ef4 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Fri, 27 Mar 2026 08:43:17 +0000 Subject: [PATCH 46/50] [BOT] post-merge updates --- odoo_repository_migration/README.rst | 2 +- odoo_repository_migration/__manifest__.py | 2 +- odoo_repository_migration/static/description/index.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/odoo_repository_migration/README.rst b/odoo_repository_migration/README.rst index d643be3a..ec3192f0 100644 --- a/odoo_repository_migration/README.rst +++ b/odoo_repository_migration/README.rst @@ -11,7 +11,7 @@ Odoo Repository Migration Data !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:897a7456693242289caa6a0ae4c8e32ea2c2d336832aa6ef5a4e50262e2865e6 + !! source digest: sha256:568479ec26f358ee26894cc3b2409f3337827426661abba55f0e3f3b8db19cc3 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/odoo_repository_migration/__manifest__.py b/odoo_repository_migration/__manifest__.py index 1fbde63e..de0bc143 100644 --- a/odoo_repository_migration/__manifest__.py +++ b/odoo_repository_migration/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Odoo Repository Migration Data", "summary": "Collect modules migration data for Odoo Repositories.", - "version": "16.0.1.3.2", + "version": "16.0.1.3.3", "category": "Tools", "author": "Camptocamp, Odoo Community Association (OCA)", "website": "https://github.com/OCA/module-composition-analysis", diff --git a/odoo_repository_migration/static/description/index.html b/odoo_repository_migration/static/description/index.html index b7f783c6..a326915b 100644 --- a/odoo_repository_migration/static/description/index.html +++ b/odoo_repository_migration/static/description/index.html @@ -372,7 +372,7 @@

Odoo Repository Migration Data

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:897a7456693242289caa6a0ae4c8e32ea2c2d336832aa6ef5a4e50262e2865e6 +!! source digest: sha256:568479ec26f358ee26894cc3b2409f3337827426661abba55f0e3f3b8db19cc3 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/module-composition-analysis Translate me on Weblate Try me on Runboat

This module collects and records modules migration data from Odoo From 4720a6e04a4bcb2efca0413e0260792e8c463618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Mon, 30 Mar 2026 12:43:55 +0200 Subject: [PATCH 47/50] [IMP] odoo_repository_migration: pre-commit auto fixes --- odoo_repository_migration/data/queue_job.xml | 34 ++-- odoo_repository_migration/pyproject.toml | 3 + .../views/odoo_migration_path.xml | 70 ++++--- .../views/odoo_module_branch.xml | 74 ++++---- .../views/odoo_module_branch_migration.xml | 174 +++++++++--------- .../views/odoo_module_branch_timeline.xml | 132 ++++++------- .../views/odoo_repository.xml | 22 +-- requirements.txt | 1 + 8 files changed, 254 insertions(+), 256 deletions(-) create mode 100644 odoo_repository_migration/pyproject.toml diff --git a/odoo_repository_migration/data/queue_job.xml b/odoo_repository_migration/data/queue_job.xml index 448affa1..37a5d3ee 100644 --- a/odoo_repository_migration/data/queue_job.xml +++ b/odoo_repository_migration/data/queue_job.xml @@ -2,30 +2,28 @@ + + odoo_repository_scan_migration + + - - odoo_repository_scan_migration - - - - - - _scan_migration_paths - - - + + _scan_migration_paths + + + - - - _scan_migration_module - - - - + + _scan_migration_module + + + diff --git a/odoo_repository_migration/pyproject.toml b/odoo_repository_migration/pyproject.toml new file mode 100644 index 00000000..4231d0cc --- /dev/null +++ b/odoo_repository_migration/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/odoo_repository_migration/views/odoo_migration_path.xml b/odoo_repository_migration/views/odoo_migration_path.xml index a2c5c716..d7766d81 100644 --- a/odoo_repository_migration/views/odoo_migration_path.xml +++ b/odoo_repository_migration/views/odoo_migration_path.xml @@ -2,14 +2,13 @@ - - - odoo.migration.path.form - odoo.migration.path - -

-
-
- - - - - - -
- - + + + + + + + + + + - - odoo.migration.path.tree - odoo.migration.path - - - - - - - + + odoo.migration.path.tree + odoo.migration.path + + + + + + + - - Migration Paths - ir.actions.act_window - odoo.migration.path - - + + Migration Paths + ir.actions.act_window + odoo.migration.path + + - - diff --git a/odoo_repository_migration/views/odoo_module_branch.xml b/odoo_repository_migration/views/odoo_module_branch.xml index 302deea1..abe6aaff 100644 --- a/odoo_repository_migration/views/odoo_module_branch.xml +++ b/odoo_repository_migration/views/odoo_module_branch.xml @@ -2,57 +2,55 @@ - - - odoo.module.branch.form.inherit - odoo.module.branch - - -
- - -
- - - - - - - - - - - - -
-
+ Next Versions + +
+ + + + + + + + + + + + +
+ - - odoo.module.branch.search.inherit - odoo.module.branch - - - - + odoo.module.branch.search.inherit + odoo.module.branch + + + + - - - - - +
+
+
diff --git a/odoo_repository_migration/views/odoo_module_branch_migration.xml b/odoo_repository_migration/views/odoo_module_branch_migration.xml index 15b53d0a..5d2aecb3 100644 --- a/odoo_repository_migration/views/odoo_module_branch_migration.xml +++ b/odoo_repository_migration/views/odoo_module_branch_migration.xml @@ -2,152 +2,152 @@ - - - odoo.module.branch.migration.form - odoo.module.branch.migration - -
- -
-

-
- - - - + odoo.module.branch.migration.form + odoo.module.branch.migration + + + +
+

+ +

+
+ + + + - - - - - - - - - - - - - - -
- -
-
+ + + + + + + + + + + + + + + + + - - odoo.module.branch.migration.tree - odoo.module.branch.migration - - - - - - - - - - - - + + odoo.module.branch.migration.tree + odoo.module.branch.migration + + + + + + + + + + + + - - odoo.module.branch.migration.search - odoo.module.branch.migration - search - - - - - - - - - - - - + odoo.module.branch.migration.search + odoo.module.branch.migration + search + + + + + + + + + + + + - - - - - + - - - - - - - - - - + + + + - - Migrations - ir.actions.act_window - odoo.module.branch.migration - - + Migrations + ir.actions.act_window + odoo.module.branch.migration + + {'search_default_group_by_migration_path_id': 1, 'search_default_group_by_state': 2} - + - -
diff --git a/odoo_repository_migration/views/odoo_module_branch_timeline.xml b/odoo_repository_migration/views/odoo_module_branch_timeline.xml index 60ec528a..e5ca6c9f 100644 --- a/odoo_repository_migration/views/odoo_module_branch_timeline.xml +++ b/odoo_repository_migration/views/odoo_module_branch_timeline.xml @@ -2,101 +2,103 @@ - - - odoo.module.branch.timeline.form - odoo.module.branch.timeline - -
- - - - - - - + odoo.module.branch.timeline.form + odoo.module.branch.timeline + + + + + + + + + - - - - - - - -
+ + + + + + + + - - odoo.module.branch.timeline.tree - odoo.module.branch.timeline - - - - - - - - - + + odoo.module.branch.timeline.tree + odoo.module.branch.timeline + + + + + + + + + - - odoo.module.branch.timeline.search - odoo.module.branch.timeline - search - - - - - - - - - - + odoo.module.branch.timeline.search + odoo.module.branch.timeline + search + + + + + + + + + + - - + - - - - - - - + + + + - - Timelines - ir.actions.act_window - odoo.module.branch.timeline - - {'search_default_group_by_org_id': 1} - + + Timelines + ir.actions.act_window + odoo.module.branch.timeline + + {'search_default_group_by_org_id': 1} + - -
diff --git a/odoo_repository_migration/views/odoo_repository.xml b/odoo_repository_migration/views/odoo_repository.xml index a8961598..67418efa 100644 --- a/odoo_repository_migration/views/odoo_repository.xml +++ b/odoo_repository_migration/views/odoo_repository.xml @@ -2,16 +2,14 @@ - - - odoo.repository.form.inherit - odoo.repository - - - - - - - - + + odoo.repository.form.inherit + odoo.repository + + + + + + + diff --git a/requirements.txt b/requirements.txt index 1130c184..977fea36 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ # generated from manifests external_dependencies gitpython +oca-port odoo-addons-parser pyyaml From 9cb1a5dd9d39e1b71f9793fe589f7920d760602b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Mon, 30 Mar 2026 12:48:23 +0200 Subject: [PATCH 48/50] [IMP] odoo_repository_migration: pre-commit fixes --- odoo_repository_migration/models/odoo_module_branch.py | 5 ++++- odoo_repository_migration/models/odoo_repository.py | 4 ++-- odoo_repository_migration/tests/test_odoo_module_branch.py | 3 ++- odoo_repository_migration/utils/scanner.py | 4 +++- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/odoo_repository_migration/models/odoo_module_branch.py b/odoo_repository_migration/models/odoo_module_branch.py index 62e40d81..683572af 100644 --- a/odoo_repository_migration/models/odoo_module_branch.py +++ b/odoo_repository_migration/models/odoo_module_branch.py @@ -25,7 +25,10 @@ class OdooModuleBranch(models.Model): migration_scan = fields.Boolean( compute="_compute_migration_scan", store=True, - help="Technical field telling if this module is elligible for a migration scan.", + help=( + "Technical field telling if this module is elligible " + "for a migration scan." + ), ) @api.depends("branch_id.next_id", "timeline_ids") diff --git a/odoo_repository_migration/models/odoo_repository.py b/odoo_repository_migration/models/odoo_repository.py index dcf6f907..ef01706d 100644 --- a/odoo_repository_migration/models/odoo_repository.py +++ b/odoo_repository_migration/models/odoo_repository.py @@ -82,10 +82,10 @@ def _create_subsequent_jobs( migration_paths_param = {} for migration_path in migration_paths: source_rb = self.branch_ids.filtered( - lambda rb: rb.branch_id == migration_path.source_branch_id + lambda rb, mp=migration_path: rb.branch_id == mp.source_branch_id ) target_rb = self.branch_ids.filtered( - lambda rb: rb.branch_id == migration_path.target_branch_id + lambda rb, mp=migration_path: rb.branch_id == mp.target_branch_id ) # Need the two Odoo versions of the migration path available # in the scanned repository diff --git a/odoo_repository_migration/tests/test_odoo_module_branch.py b/odoo_repository_migration/tests/test_odoo_module_branch.py index 8da7cc45..b62ca072 100644 --- a/odoo_repository_migration/tests/test_odoo_module_branch.py +++ b/odoo_repository_migration/tests/test_odoo_module_branch.py @@ -183,7 +183,8 @@ def test_migration_scan_target_module_in_review_then_merged(self): self.assertTrue(self.module_branch.migration_ids.migration_scan) self.assertTrue(self.module_branch.migration_scan) # Simulate the migration scan. - # The source module is fully ported and doesn't need a migration scan afterwards. + # The source module is fully ported and doesn't need a migration + # scan afterwards. self._simulate_migration_scan("target_commit2", report={"results": {}}) self.assertEqual(self.module_branch.migration_ids.state, "fully_ported") self.assertFalse(self.module_branch.migration_ids.migration_scan) diff --git a/odoo_repository_migration/utils/scanner.py b/odoo_repository_migration/utils/scanner.py index 18f01796..f377e181 100644 --- a/odoo_repository_migration/utils/scanner.py +++ b/odoo_repository_migration/utils/scanner.py @@ -81,7 +81,9 @@ def _get_odoo_module_branch_migration_data( migration = self.env["odoo.module.branch.migration"].search(args) if migration: data = { - "last_source_scanned_commit": migration.module_branch_id.last_scanned_commit, + "last_source_scanned_commit": ( + migration.module_branch_id.last_scanned_commit + ), "last_target_scanned_commit": ( migration.target_module_branch_id.last_scanned_commit ), From 9669e9ef8e934d146a3da4a8a29314e29ddeb54c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Mon, 30 Mar 2026 12:49:20 +0200 Subject: [PATCH 49/50] [MIG] odoo_repository_migration: Migration to 18.0 --- odoo_repository_migration/__manifest__.py | 2 +- odoo_repository_migration/hooks.py | 5 +- .../migrations/16.0.1.0.1/post-migration.py | 22 -------- .../migrations/16.0.1.1.0/post-migration.py | 26 --------- .../migrations/16.0.1.2.0/post-migration.py | 56 ------------------- .../migrations/16.0.1.3.0/post-migration.py | 35 ------------ .../views/odoo_migration_path.xml | 6 +- .../views/odoo_module_branch.xml | 6 +- .../views/odoo_module_branch_migration.xml | 10 ++-- .../views/odoo_module_branch_timeline.xml | 8 +-- 10 files changed, 17 insertions(+), 159 deletions(-) delete mode 100644 odoo_repository_migration/migrations/16.0.1.0.1/post-migration.py delete mode 100644 odoo_repository_migration/migrations/16.0.1.1.0/post-migration.py delete mode 100644 odoo_repository_migration/migrations/16.0.1.2.0/post-migration.py delete mode 100644 odoo_repository_migration/migrations/16.0.1.3.0/post-migration.py diff --git a/odoo_repository_migration/__manifest__.py b/odoo_repository_migration/__manifest__.py index de0bc143..f8dd27e1 100644 --- a/odoo_repository_migration/__manifest__.py +++ b/odoo_repository_migration/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Odoo Repository Migration Data", "summary": "Collect modules migration data for Odoo Repositories.", - "version": "16.0.1.3.3", + "version": "18.0.1.0.0", "category": "Tools", "author": "Camptocamp, Odoo Community Association (OCA)", "website": "https://github.com/OCA/module-composition-analysis", diff --git a/odoo_repository_migration/hooks.py b/odoo_repository_migration/hooks.py index ee035c26..203aa658 100644 --- a/odoo_repository_migration/hooks.py +++ b/odoo_repository_migration/hooks.py @@ -1,12 +1,9 @@ # Copyright 2023 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) -from odoo import SUPERUSER_ID, api - -def update_oca_repositories(cr, registry): +def update_oca_repositories(env): """Configure OCA repositories to collect migration data.""" - env = api.Environment(cr, SUPERUSER_ID, {}) org = env["odoo.repository.org"].search([("name", "=", "OCA")]) if org: repositories = ( diff --git a/odoo_repository_migration/migrations/16.0.1.0.1/post-migration.py b/odoo_repository_migration/migrations/16.0.1.0.1/post-migration.py deleted file mode 100644 index 8262205f..00000000 --- a/odoo_repository_migration/migrations/16.0.1.0.1/post-migration.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2024 Camptocamp SA -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) - -import logging - -from odoo import SUPERUSER_ID, api - -_logger = logging.getLogger(__name__) - - -def migrate(cr, version): - if not version: - return - env = api.Environment(cr, SUPERUSER_ID, {}) - recompute_migration_scan(env) - - -def recompute_migration_scan(env): - _logger.info("Recompute '.migration_scan' field...") - mods = env["odoo.module.branch"].search([]) - mods.modified(["last_scanned_commit"]) - mods.flush_recordset(["migration_scan"]) diff --git a/odoo_repository_migration/migrations/16.0.1.1.0/post-migration.py b/odoo_repository_migration/migrations/16.0.1.1.0/post-migration.py deleted file mode 100644 index 7de23bfe..00000000 --- a/odoo_repository_migration/migrations/16.0.1.1.0/post-migration.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2024 Camptocamp SA -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) - -import logging - -from odoo import SUPERUSER_ID, api - -_logger = logging.getLogger(__name__) - - -def migrate(cr, version): - if not version: - return - env = api.Environment(cr, SUPERUSER_ID, {}) - recompute_migration_scan(env) - - -def recompute_migration_scan(env): - _logger.info("Recompute '.migration_scan' field...") - mb_model = env["odoo.module.branch"] - mods = mb_model.search([]) - mods.modified(["last_scanned_commit"]) - mods.flush_recordset(["migration_scan"]) - # Reset last target scanned commit on those that need a migration scan - mods_to_scan = mb_model.search([("migration_scan", "=", True)]) - mods_to_scan.migration_ids.write({"last_target_scanned_commit": False}) diff --git a/odoo_repository_migration/migrations/16.0.1.2.0/post-migration.py b/odoo_repository_migration/migrations/16.0.1.2.0/post-migration.py deleted file mode 100644 index 471bdb3e..00000000 --- a/odoo_repository_migration/migrations/16.0.1.2.0/post-migration.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2024 Camptocamp SA -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) - -import logging - -from odoo import SUPERUSER_ID, api - -_logger = logging.getLogger(__name__) - - -def migrate(cr, version): - if not version: - return - env = api.Environment(cr, SUPERUSER_ID, {}) - fix_migration_states(env) - - -def fix_migration_states(env): - _logger.info("Plan a scan to fix '.state' field...") - query = """ - SELECT mig.id - FROM odoo_module_branch_migration mig - JOIN odoo_module_branch AS source - ON mig.module_branch_id=source.id - JOIN odoo_module_branch AS target - ON mig.target_module_branch_id=target.id - WHERE source.repository_branch_id IS NOT NULL - AND target.repository_branch_id IS NOT NULL - AND source.repository_id != target.repository_id; - """ - env.cr.execute(query) - mig_ids = [row[0] for row in env.cr.fetchall()] - # Reset 'last_target_scanned_commit' to recompute 'migration_scan' - if mig_ids: - query = """ - UPDATE odoo_module_branch_migration - SET last_target_scanned_commit=NULL - WHERE id IN %s; - """ - args = (tuple(mig_ids),) - env.cr.execute(query, args) - # Reset collected migration data on modules that shouldn't have any - mbm_model = env["odoo.module.branch.migration"] - migs = mbm_model.search( - [ - ("results", "!=", False), - ("repository_id.collect_migration_data", "=", False), - ] - ) - migs.results = False - # Recompute migration state/flag, especially for modules moved to another repo - # that won't trigger a migration scan. - migs = mbm_model.search([("id", "in", mig_ids)]) - env.add_to_compute(migs._fields["state"], migs) - env.add_to_compute(migs._fields["migration_scan"], migs) - migs.modified(["state", "migration_scan"]) diff --git a/odoo_repository_migration/migrations/16.0.1.3.0/post-migration.py b/odoo_repository_migration/migrations/16.0.1.3.0/post-migration.py deleted file mode 100644 index af988af2..00000000 --- a/odoo_repository_migration/migrations/16.0.1.3.0/post-migration.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2025 Camptocamp SA -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) - -import logging - -from odoo import SUPERUSER_ID, api - -_logger = logging.getLogger(__name__) - - -def migrate(cr, version): - if not version: - return - env = api.Environment(cr, SUPERUSER_ID, {}) - migrate_odoo_module_branch_timelines(env) - - -def migrate_odoo_module_branch_timelines(env): - _logger.info("Migrate Odoo module timelines to 'odoo.module.branch.timeline'...") - query = """ - SELECT id, next_odoo_version_state, next_odoo_version_module_id - FROM odoo_module_branch - WHERE next_odoo_version_state != 'same'; - """ - env.cr.execute(query) - rows = env.cr.dictfetchall() - vals_list = [] - for row in rows: - vals = { - "module_branch_id": row["id"], - "state": row["next_odoo_version_state"], - "next_module_id": row["next_odoo_version_module_id"], - } - vals_list.append(vals) - env["odoo.module.branch.timeline"].create(vals_list) diff --git a/odoo_repository_migration/views/odoo_migration_path.xml b/odoo_repository_migration/views/odoo_migration_path.xml index d7766d81..ad15565b 100644 --- a/odoo_repository_migration/views/odoo_migration_path.xml +++ b/odoo_repository_migration/views/odoo_migration_path.xml @@ -28,13 +28,13 @@ - odoo.migration.path.tree + odoo.migration.path.list odoo.migration.path - + - + diff --git a/odoo_repository_migration/views/odoo_module_branch.xml b/odoo_repository_migration/views/odoo_module_branch.xml index abe6aaff..71b1df46 100644 --- a/odoo_repository_migration/views/odoo_module_branch.xml +++ b/odoo_repository_migration/views/odoo_module_branch.xml @@ -14,7 +14,7 @@ type="object" class="oe_stat_button" icon="fa-arrow-up" - attrs="{'invisible': [('next_odoo_version_module_branch_id', '=', False)]}" + invisible="not next_odoo_version_module_branch_id" > Next Versions @@ -22,12 +22,12 @@ - + - + diff --git a/odoo_repository_migration/views/odoo_module_branch_migration.xml b/odoo_repository_migration/views/odoo_module_branch_migration.xml index 5d2aecb3..8a5b311d 100644 --- a/odoo_repository_migration/views/odoo_module_branch_migration.xml +++ b/odoo_repository_migration/views/odoo_module_branch_migration.xml @@ -18,11 +18,11 @@ @@ -43,10 +43,10 @@ - odoo.module.branch.migration.tree + odoo.module.branch.migration.list odoo.module.branch.migration - + @@ -54,7 +54,7 @@ - + diff --git a/odoo_repository_migration/views/odoo_module_branch_timeline.xml b/odoo_repository_migration/views/odoo_module_branch_timeline.xml index e5ca6c9f..eb20d374 100644 --- a/odoo_repository_migration/views/odoo_module_branch_timeline.xml +++ b/odoo_repository_migration/views/odoo_module_branch_timeline.xml @@ -15,7 +15,7 @@ @@ -27,15 +27,15 @@ - odoo.module.branch.timeline.tree + odoo.module.branch.timeline.list odoo.module.branch.timeline - + - + From 2d3977c3fe506d89f6013f4843f6c2b010a19eec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alix?= Date: Mon, 30 Mar 2026 14:05:28 +0200 Subject: [PATCH 50/50] [FIX] odoo_repository: tests, apply git config in repository --- odoo_repository/tests/odoo_repo_mixin.py | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/odoo_repository/tests/odoo_repo_mixin.py b/odoo_repository/tests/odoo_repo_mixin.py index 3fad1991..160355c0 100644 --- a/odoo_repository/tests/odoo_repo_mixin.py +++ b/odoo_repository/tests/odoo_repo_mixin.py @@ -2,7 +2,6 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) import io -import os import shutil import tempfile import threading @@ -31,20 +30,10 @@ def setUpClass(cls): cls.addon = "my_module" cls.target_addon = "my_module_renamed" # Create a temporary Git repository - cls._apply_git_config() cls.repo_upstream_path = cls._get_upstream_repository_path() cls.addon_path = Path(cls.repo_upstream_path) / cls.addon cls.manifest_path = cls.addon_path / "__manifest__.py" - @classmethod - def _apply_git_config(cls): - """Configure git (~/.gitconfig) if no config file exists.""" - git_cfg = Path(os.path.expanduser("~/.gitconfig")) - if git_cfg.exists(): - return - os.system("git config --global user.email 'test@example.com'") - os.system("git config --global user.name 'test'") - @classmethod def _get_upstream_repository_path(cls) -> Path: """Returns the path of upstream repository. @@ -95,7 +84,9 @@ def _unarchive_upstream_repository(cls, archive_data: bytes) -> Path: def _create_tmp_git_repository(cls) -> Path: """Create a temporary Git repository to run tests.""" repo_path = tempfile.mkdtemp() - git.Repo.init(repo_path) + repo = git.Repo.init(repo_path) + repo.config_writer().set_value("user", "name", "test").release() + repo.config_writer().set_value("user", "email", "test@example.com").release() return Path(repo_path) @classmethod