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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions odoo_project_migration/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from . import odoo_module_branch_migration
from . import odoo_project_module
from . import odoo_project_module_migration
from . import odoo_project
12 changes: 12 additions & 0 deletions odoo_project_migration/models/odoo_project_module.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright 2025 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)

from odoo import models


class OdooProjectModule(models.Model):
_inherit = "odoo.project.module"

def open_next_module_branches(self):
self.ensure_one()
return self.module_branch_id.open_next_module_branches()
50 changes: 25 additions & 25 deletions odoo_project_migration/models/odoo_project_module_migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,10 @@ class OdooProjectModuleMigration(models.Model):
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"),
# New states to qualify modules without migration data
Expand All @@ -121,13 +122,24 @@ def _compute_project_module_id(self):
)
rec.project_module_id = project_module

@api.depends("source_module_branch_id", "migration_path_id")
@api.depends(
"source_module_branch_id",
"migration_path_id",
"module_migration_id.replaced_by_module_id",
"module_migration_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.module_migration_id.replaced_by_module_id
or rec.module_migration_id.renamed_to_module_id
or rec.source_module_branch_id.module_id
)
rec.target_module_branch_id = module_branch_model._find(
rec.migration_path_id.target_branch_id,
rec.source_module_branch_id.module_id,
module,
rec.odoo_project_id.repository_id,
domain=[("installable", "=", True)],
)
Expand Down Expand Up @@ -159,27 +171,15 @@ def _compute_migration_script_ids(self):
],
order="sequence",
)
new_release_versions = version_model.search(
[
(
"module_id",
"=",
rec.module_id.id,
),
(
"branch_sequence",
">",
rec.source_module_branch_id.branch_id.sequence,
),
(
"branch_sequence",
"<=",
rec.target_module_branch_id.branch_id.sequence,
),
("has_migration_script", "=", True),
],
order="branch_sequence, sequence",
# Collect versions with migration scripts accross next modules
# taking into account module renaming/replacement
target_branch = rec.migration_path_id.target_branch_id
next_modules = rec.source_module_branch_id._get_next_module_branches(
target_branch
)
new_release_versions = next_modules.version_ids.filtered(
"has_migration_script"
).sorted(key=lambda v: (v.branch_sequence, v.sequence))
rec.migration_script_ids = current_release_versions | new_release_versions

@api.depends("module_migration_id.state")
Expand Down
4 changes: 2 additions & 2 deletions odoo_project_migration/views/odoo_module_branch_migration.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
ref="odoo_repository_migration.odoo_module_branch_migration_view_form"
/>
<field name="arch" type="xml">
<field name="migration_scan" position="after">
<group name="info" position="inside">
<field name="odoo_project_ids" widget="many2many_tags" />
</field>
</group>
</field>
</record>

Expand Down
24 changes: 17 additions & 7 deletions odoo_project_migration/wizards/export_migration_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,16 +134,26 @@ def _prepare_csv_module_line(self, module):

def _get_csv_module_info(self, module):
migration = module.module_migration_id
info = ""
info = []
# Module renamed or replaced by another one
if migration.renamed_to_module_id:
info.append(f"Renamed to {migration.target_module_branch_id.module_name}")
elif migration.replaced_by_module_id:
info.append(
f"Replaced by {migration.target_module_branch_id.module_name} "
f"(in {migration.target_module_branch_id.repository_id.display_name})"
)
# Migration to review or commits/PRs to port
if migration.state == "review_migration":
info = migration.pr_url or ""
if migration.pr_url:
info.append(f"PR to review: {migration.pr_url}")
elif migration.process == "port_commits":
nb_prs = len(migration.results)
info = f"{nb_prs} PR(s) to check/port"
info = "\n".join(
[info] + [f"- {pr['url']}" for pr in migration.results.values()]
msg = f"{nb_prs} PR(s) to check/port"
msg = "\n".join(
[msg] + [f"- {pr['url']}" for pr in migration.results.values()]
)
info.append(msg)
# Migration scripts
if module.migration_script_ids:
nb_scripts = len(module.migration_script_ids)
Expand All @@ -152,8 +162,8 @@ def _get_csv_module_info(self, module):
[info_mig]
+ [f"- {sc.migration_script_url}" for sc in module.migration_script_ids]
)
info += info_mig
return info
info.append(info_mig)
return "\n\n".join(info)

def _get_csv_module_warning(self, module):
warning = ""
Expand Down
29 changes: 24 additions & 5 deletions odoo_repository/lib/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,10 @@ def _scan_migration_path(
module_names = self._get_module_paths(repo, addons_path, source_branch)
res = []
for module in module_names:
if isinstance(module, tuple):
module, target_module = module
else:
target_module = module
Comment on lines 510 to 513
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will change this module_names parameter later, current implementation is a bit crappy but that's OK for now.

if self._is_module_blacklisted(module):
_logger.info(
"%s: '%s' is blacklisted (no migration scan)",
Expand All @@ -532,7 +536,7 @@ def _scan_migration_path(
repo.commit(repo_source_commit).tree, module
)
module_target_tree = self._get_subtree(
repo.commit(repo_target_commit).tree, module
repo.commit(repo_target_commit).tree, target_module
)
module_source_commit = self._get_last_commit_of_git_tree(
repo_source_commit, module_source_tree
Expand All @@ -556,6 +560,7 @@ def _scan_migration_path(
repo,
addons_path,
module,
target_module,
module_branch_id,
source_branch,
target_remote,
Expand All @@ -575,6 +580,7 @@ def _scan_module(
repo: git.Repo,
addons_path: str,
module: str,
target_module: str,
module_branch_id: int,
source_branch: str,
target_remote: str,
Expand All @@ -596,6 +602,7 @@ def _scan_module(
"target_commit": target_last_scanned_commit,
}
module_path = str(pathlib.Path(addons_path).joinpath(module))
target_module_path = str(pathlib.Path(addons_path).joinpath(target_module))
# If files updated in the module since the last scan are not relevant
# (e.g. all new commits are updating PO files), we skip the scan.
source_scan_relevant = self._is_scan_module_relevant(
Expand All @@ -606,7 +613,7 @@ def _scan_module(
)
target_scan_relevant = self._is_scan_module_relevant(
repo,
module_path,
target_module_path,
target_last_mig_scanned_commit,
target_commit,
)
Expand All @@ -623,12 +630,16 @@ def _scan_module(
_logger.info(
"%s: relevant changes detected in '%s' (%s -> %s)",
self.full_name,
module,
module if source_scan_relevant else target_module,
source_branch,
target_branch,
)
oca_port_data = self._run_oca_port(
module_path, source_branch, target_remote, target_branch
module_path,
target_module_path,
source_branch,
target_remote,
target_branch,
)
data["report"] = oca_port_data
self._push_scanned_data(module_branch_id, data)
Expand Down Expand Up @@ -681,7 +692,14 @@ def _check_relevant_commits(self, repo, module_path, commits):
return True
return False

def _run_oca_port(self, module_path, source_branch, target_remote, target_branch):
def _run_oca_port(
self,
module_path,
target_module_path,
source_branch,
target_remote,
target_branch,
):
_logger.info(
"%s: collect migration data for '%s' (%s -> %s)",
self.full_name,
Expand All @@ -694,6 +712,7 @@ def _run_oca_port(self, module_path, source_branch, target_remote, target_branch
"source": f"origin/{source_branch}",
"target": f"{target_remote}/{target_branch}",
"addon_path": module_path,
"target_addon_path": target_module_path,
"upstream_org": self.org,
"repo_path": self.path,
"repo_name": self.name,
Expand Down
1 change: 1 addition & 0 deletions odoo_repository/security/ir.model.access.csv
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ access_odoo_repository_manager,odoo_repository_manager,model_odoo_repository,gro
access_odoo_repository_branch_user,odoo_repository_branch_user,model_odoo_repository_branch,group_odoo_repository_user,1,0,0,0
access_odoo_repository_branch_manager,odoo_repository_branch_manager,model_odoo_repository_branch,group_odoo_repository_manager,1,1,1,1
access_odoo_module_branch_user,odoo_module_branch_user,model_odoo_module_branch,group_odoo_repository_user,1,0,0,0
access_odoo_module_branch_manager,odoo_module_branch_manager,model_odoo_module_branch,group_odoo_repository_manager,1,1,0,0
access_odoo_module_branch_version_user,odoo_module_branch_version_user,model_odoo_module_branch_version,group_odoo_repository_user,1,0,0,0
access_odoo_module_branch_version_manager,odoo_module_branch_version_manager,model_odoo_module_branch_version,group_odoo_repository_manager,1,1,1,1
58 changes: 31 additions & 27 deletions odoo_repository/views/odoo_module_branch.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,27 @@
</div>
<group>
<group name="manifest" string="Manifest">
<field name="title" />
<field name="summary" />
<field name="author_ids" widget="many2many_tags" />
<field name="maintainer_ids" widget="many2many_tags" />
<field name="category_id" options="{'no_open': True}" />
<field name="license_id" options="{'no_open': True}" />
<field name="version" />
<field name="development_status_id" options="{'no_open': True}" />
<field name="application" />
<field name="installable" />
<field name="auto_install" />
<field name="title" readonly="1" />
<field name="summary" readonly="1" />
<field name="author_ids" widget="many2many_tags" readonly="1" />
<field name="maintainer_ids" widget="many2many_tags" readonly="1" />
<field name="category_id" options="{'no_open': True}" readonly="1" />
<field name="license_id" options="{'no_open': True}" readonly="1" />
<field name="version" readonly="1" />
<field
name="development_status_id"
options="{'no_open': True}"
readonly="1"
/>
<field name="application" readonly="1" />
<field name="installable" readonly="1" />
<field name="auto_install" readonly="1" />
</group>
<group col="1">
<group name="others" string="Others">
<field name="module_id" />
<field name="branch_id" options="{'no_open': True}" />
<field name="repository_branch_id" />
<field name="module_id" readonly="1" />
<field name="branch_id" options="{'no_open': True}" readonly="1" />
<field name="repository_branch_id" readonly="1" />
<field
name="pr_url"
widget="url"
Expand All @@ -48,25 +52,25 @@
widget="url"
attrs="{'invisible': [('pr_url', '=', True)]}"
/>
<field name="last_scanned_commit" />
<field name="removed" />
<field name="is_standard" />
<field name="is_enterprise" />
<field name="is_community" />
<field name="last_scanned_commit" readonly="1" />
<field name="removed" readonly="1" />
<field name="is_standard" readonly="1" />
<field name="is_enterprise" readonly="1" />
<field name="is_community" readonly="1" />
<field name="global_dependency_level" />
<field name="non_std_dependency_level" />
</group>
<group name="code" string="Code analysis">
<field name="sloc_python" />
<field name="sloc_xml" />
<field name="sloc_js" />
<field name="sloc_css" />
<field name="sloc_python" readonly="1" />
<field name="sloc_xml" readonly="1" />
<field name="sloc_js" readonly="1" />
<field name="sloc_css" readonly="1" />
</group>
</group>
</group>
<notebook>
<page name="versions" string="Versions">
<field name="version_ids" nolabel="1">
<field name="version_ids" nolabel="1" readonly="1">
<tree>
<field name="name" />
<field name="commit" />
Expand All @@ -75,7 +79,7 @@
</field>
</page>
<page name="dependencies" string="Dependencies">
<field name="dependency_ids" nolabel="1">
<field name="dependency_ids" nolabel="1" readonly="1">
<tree>
<field name="module_id" />
<field name="repository_branch_id" />
Expand All @@ -88,7 +92,7 @@
</field>
</page>
<page name="reverse_dependencies" string="Reverse Dependencies">
<field name="reverse_dependency_ids" nolabel="1">
<field name="reverse_dependency_ids" nolabel="1" readonly="1">
<tree>
<field name="module_id" />
<field name="repository_branch_id" />
Expand All @@ -101,7 +105,7 @@
</field>
</page>
<page name="python_dependency_ids" string="Python Dependencies">
<field name="python_dependency_ids" nolabel="1" />
<field name="python_dependency_ids" nolabel="1" readonly="1" />
</page>
</notebook>
</sheet>
Expand Down
Loading