From 8333e656d88c81f4dc35cc8e7186d4eb97bbd8a4 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Sun, 1 Mar 2026 18:37:29 +0100 Subject: [PATCH 01/21] [IMP] [ADD] vpc_odoo: entry menu item for vcp.odoo.module.version --- vcp_odoo/__manifest__.py | 3 ++- vcp_odoo/views/menu.xml | 25 ++++++++++++++++++++++ vcp_odoo/views/vcp_odoo_module.xml | 9 +------- vcp_odoo/views/vcp_odoo_module_version.xml | 8 +++++++ 4 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 vcp_odoo/views/menu.xml diff --git a/vcp_odoo/__manifest__.py b/vcp_odoo/__manifest__.py index 91db677..4270837 100644 --- a/vcp_odoo/__manifest__.py +++ b/vcp_odoo/__manifest__.py @@ -11,9 +11,10 @@ "depends": ["vcp_management"], "data": [ "security/ir.model.access.csv", - "views/vcp_odoo_module_version.xml", "views/vcp_odoo_module.xml", + "views/vcp_odoo_module_version.xml", "views/vcp_rule.xml", + "views/menu.xml", "data/vcp_rule.xml", ], "demo": [], diff --git a/vcp_odoo/views/menu.xml b/vcp_odoo/views/menu.xml new file mode 100644 index 0000000..4cd05c1 --- /dev/null +++ b/vcp_odoo/views/menu.xml @@ -0,0 +1,25 @@ + + + + + + + + + diff --git a/vcp_odoo/views/vcp_odoo_module.xml b/vcp_odoo/views/vcp_odoo_module.xml index 105d54a..9d47fc6 100644 --- a/vcp_odoo/views/vcp_odoo_module.xml +++ b/vcp_odoo/views/vcp_odoo_module.xml @@ -51,17 +51,10 @@ - Odoo Modules + Modules vcp.odoo.module list,form [] {'search_default_filter_with_version': 1} - - - Odoo Modules - - - - diff --git a/vcp_odoo/views/vcp_odoo_module_version.xml b/vcp_odoo/views/vcp_odoo_module_version.xml index 8e1a514..d98e8b2 100644 --- a/vcp_odoo/views/vcp_odoo_module_version.xml +++ b/vcp_odoo/views/vcp_odoo_module_version.xml @@ -64,4 +64,12 @@ + + + Module Versions + vcp.odoo.module.version + list,form + [] + {} + From 93f6094f2077bd650754a6ee7371fca62b54a95c Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Sun, 1 Mar 2026 18:41:48 +0100 Subject: [PATCH 02/21] [FIX] vcp_odoo: set readonly on all 'vcp.odoo.xxx' model fields --- vcp_odoo/models/vcp_odoo_bin_package.py | 2 +- vcp_odoo/models/vcp_odoo_lib_python.py | 2 +- vcp_odoo/models/vcp_odoo_module.py | 6 ++++-- vcp_odoo/models/vcp_odoo_module_version.py | 16 ++++++++++++---- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/vcp_odoo/models/vcp_odoo_bin_package.py b/vcp_odoo/models/vcp_odoo_bin_package.py index 2625e28..5209a46 100644 --- a/vcp_odoo/models/vcp_odoo_bin_package.py +++ b/vcp_odoo/models/vcp_odoo_bin_package.py @@ -8,7 +8,7 @@ class VcpOdooBinPackage(models.Model): _name = "vcp.odoo.bin.package" _description = "Binary Package required by an Odoo Module" - name = fields.Char(required=True) + name = fields.Char(required=True, readonly=True) @tools.ormcache("name") def _get_bin(self, name): diff --git a/vcp_odoo/models/vcp_odoo_lib_python.py b/vcp_odoo/models/vcp_odoo_lib_python.py index 2759f3c..31e83b1 100644 --- a/vcp_odoo/models/vcp_odoo_lib_python.py +++ b/vcp_odoo/models/vcp_odoo_lib_python.py @@ -8,7 +8,7 @@ class VcpOdooLibPython(models.Model): _name = "vcp.odoo.lib.python" _description = "Python Library required by an Odoo Module" - name = fields.Char(required=True) + name = fields.Char(required=True, readonly=True) @tools.ormcache("name") def _get_lib_python(self, name): diff --git a/vcp_odoo/models/vcp_odoo_module.py b/vcp_odoo/models/vcp_odoo_module.py index 479107e..7f6ee71 100644 --- a/vcp_odoo/models/vcp_odoo_module.py +++ b/vcp_odoo/models/vcp_odoo_module.py @@ -8,8 +8,10 @@ class VcpOdooModule(models.Model): _name = "vcp.odoo.module" _description = "Odoo Module" - name = fields.Char(required=True) - version_ids = fields.One2many("vcp.odoo.module.version", inverse_name="module_id") + name = fields.Char(required=True, readonly=True) + version_ids = fields.One2many( + "vcp.odoo.module.version", inverse_name="module_id", readonly=True + ) version_count = fields.Integer( compute="_compute_version_count", help="number of versions in which the module is available", diff --git a/vcp_odoo/models/vcp_odoo_module_version.py b/vcp_odoo/models/vcp_odoo_module_version.py index 363f860..4a33c8f 100644 --- a/vcp_odoo/models/vcp_odoo_module_version.py +++ b/vcp_odoo/models/vcp_odoo_module_version.py @@ -9,33 +9,41 @@ class VcpOdooModuleVersion(models.Model): _description = "Odoo Module on an specific repository branch" _inherit = ["vcp.rule.information.mixin", "image.mixin"] - name = fields.Char(required=True) - path = fields.Char(required=True) + name = fields.Char(required=True, readonly=True) + path = fields.Char(required=True, readonly=True) module_id = fields.Many2one( "vcp.odoo.module", + readonly=True, required=True, ondelete="cascade", ) - version = fields.Char(required=True) + version = fields.Char( + required=True, + readonly=True, + ) repository_branch_id = fields.Many2one( "vcp.repository.branch", + readonly=True, required=True, ondelete="cascade", ) depends_on_module_ids = fields.Many2many( "vcp.odoo.module", + readonly=True, ) - auto_install = fields.Boolean() + auto_install = fields.Boolean(readonly=True) license = fields.Char(string="License (Manifest)", readonly=True) summary = fields.Char(string="Summary (Manifest)", readonly=True) website = fields.Char(string="Website (Manifest)", readonly=True) lib_python_ids = fields.Many2many( "vcp.odoo.lib.python", string="Python Libraries", + readonly=True, ) bin_package_ids = fields.Many2many( "vcp.odoo.bin.package", string="Python Binaries", + readonly=True, ) def _get_local_path(self): From ff510646aded2f41c805d0a43cdae9cca731c2ab Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Sun, 1 Mar 2026 19:05:31 +0100 Subject: [PATCH 03/21] [REF] vcp_odoo: rename vcp.odoo.lib.python into vcp.odoo.python.library. (following similar logic with the modele bin.package) --- vcp_odoo/models/__init__.py | 2 +- vcp_odoo/models/vcp_odoo_bin_package.py | 2 +- vcp_odoo/models/vcp_odoo_module_version.py | 4 ++-- ...p_odoo_lib_python.py => vcp_odoo_python_library.py} | 6 +++--- vcp_odoo/models/vcp_rule.py | 10 +++++++--- vcp_odoo/security/ir.model.access.csv | 4 ++-- vcp_odoo/views/vcp_odoo_module_version.xml | 2 +- 7 files changed, 17 insertions(+), 13 deletions(-) rename vcp_odoo/models/{vcp_odoo_lib_python.py => vcp_odoo_python_library.py} (77%) diff --git a/vcp_odoo/models/__init__.py b/vcp_odoo/models/__init__.py index be6d37f..dd294a2 100644 --- a/vcp_odoo/models/__init__.py +++ b/vcp_odoo/models/__init__.py @@ -2,4 +2,4 @@ from . import vcp_odoo_module from . import vcp_odoo_module_version from . import vcp_odoo_bin_package -from . import vcp_odoo_lib_python +from . import vcp_odoo_python_library diff --git a/vcp_odoo/models/vcp_odoo_bin_package.py b/vcp_odoo/models/vcp_odoo_bin_package.py index 5209a46..5eaf521 100644 --- a/vcp_odoo/models/vcp_odoo_bin_package.py +++ b/vcp_odoo/models/vcp_odoo_bin_package.py @@ -11,7 +11,7 @@ class VcpOdooBinPackage(models.Model): name = fields.Char(required=True, readonly=True) @tools.ormcache("name") - def _get_bin(self, name): + def _get_bin_package(self, name): bin_src = self.search([("name", "=", name)], limit=1) if not bin_src: bin_src = self.create({"name": name}) diff --git a/vcp_odoo/models/vcp_odoo_module_version.py b/vcp_odoo/models/vcp_odoo_module_version.py index 4a33c8f..0dbc0c0 100644 --- a/vcp_odoo/models/vcp_odoo_module_version.py +++ b/vcp_odoo/models/vcp_odoo_module_version.py @@ -35,8 +35,8 @@ class VcpOdooModuleVersion(models.Model): license = fields.Char(string="License (Manifest)", readonly=True) summary = fields.Char(string="Summary (Manifest)", readonly=True) website = fields.Char(string="Website (Manifest)", readonly=True) - lib_python_ids = fields.Many2many( - "vcp.odoo.lib.python", + python_library_ids = fields.Many2many( + "vcp.odoo.python.library", string="Python Libraries", readonly=True, ) diff --git a/vcp_odoo/models/vcp_odoo_lib_python.py b/vcp_odoo/models/vcp_odoo_python_library.py similarity index 77% rename from vcp_odoo/models/vcp_odoo_lib_python.py rename to vcp_odoo/models/vcp_odoo_python_library.py index 31e83b1..3031fa1 100644 --- a/vcp_odoo/models/vcp_odoo_lib_python.py +++ b/vcp_odoo/models/vcp_odoo_python_library.py @@ -4,14 +4,14 @@ from odoo import fields, models, tools -class VcpOdooLibPython(models.Model): - _name = "vcp.odoo.lib.python" +class VcpOdooPythonLibrary(models.Model): + _name = "vcp.odoo.python.library" _description = "Python Library required by an Odoo Module" name = fields.Char(required=True, readonly=True) @tools.ormcache("name") - def _get_lib_python(self, name): + def _get_python_library(self, name): lib = self.search([("name", "=", name)], limit=1) if not lib: lib = self.create({"name": name}) diff --git a/vcp_odoo/models/vcp_rule.py b/vcp_odoo/models/vcp_rule.py index a9309ea..8d5f74d 100644 --- a/vcp_odoo/models/vcp_rule.py +++ b/vcp_odoo/models/vcp_rule.py @@ -92,10 +92,14 @@ def _process_rule_odoo_module_prepare_vals( break python_libs = [] for lib in manifest.get("external_dependencies", {}).get("python", []): - python_libs.append(self.env["vcp.odoo.lib.python"]._get_lib_python(lib)) + python_libs.append( + self.env["vcp.odoo.python.library"]._get_python_library(lib) + ) package_bins = [] for package_bin in manifest.get("external_dependencies", {}).get("bin", []): - package_bins.append(self.env["vcp.odoo.bin.package"]._get_bin(package_bin)) + package_bins.append( + self.env["vcp.odoo.bin.package"]._get_bin_package(package_bin) + ) return { "name": manifest.get("name"), "module_id": module_id, @@ -112,6 +116,6 @@ def _process_rule_odoo_module_prepare_vals( "repository_branch_id": repository_branch.id, "depends_on_module_ids": [Command.set(depends)], "image_1920": icon, - "lib_python_ids": [Command.set(python_libs)], + "python_library_ids": [Command.set(python_libs)], "bin_package_ids": [Command.set(package_bins)], } diff --git a/vcp_odoo/security/ir.model.access.csv b/vcp_odoo/security/ir.model.access.csv index bad4a4f..0a29ab7 100644 --- a/vcp_odoo/security/ir.model.access.csv +++ b/vcp_odoo/security/ir.model.access.csv @@ -5,5 +5,5 @@ access_vcp_odoo_module_version,Access Odoo Module Version,model_vcp_odoo_module_ manage_vcp_odoo_module_version,Manage Odoo Module Version,model_vcp_odoo_module_version,vcp_management.group_vcp_manager,1,1,1,0 access_vcp_odoo_bin_package,Access Odoo Bin Package,model_vcp_odoo_bin_package,vcp_management.group_vcp_user,1,0,0,0 manage_vcp_odoo_bin_package,Manage Odoo Bin Package,model_vcp_odoo_bin_package,vcp_management.group_vcp_manager,1,1,1,0 -access_vcp_odoo_lib_python,Access Odoo Python Library,model_vcp_odoo_lib_python,vcp_management.group_vcp_user,1,0,0,0 -manage_vcp_odoo_lib_python,Manage Odoo Python Library,model_vcp_odoo_lib_python,vcp_management.group_vcp_manager,1,1,1,0 +access_vcp_odoo_python_library,Access Odoo Python Library,model_vcp_odoo_python_library,vcp_management.group_vcp_user,1,0,0,0 +manage_vcp_odoo_python_library,Manage Odoo Python Library,model_vcp_odoo_python_library,vcp_management.group_vcp_manager,1,1,1,0 diff --git a/vcp_odoo/views/vcp_odoo_module_version.xml b/vcp_odoo/views/vcp_odoo_module_version.xml index d98e8b2..8f43e21 100644 --- a/vcp_odoo/views/vcp_odoo_module_version.xml +++ b/vcp_odoo/views/vcp_odoo_module_version.xml @@ -26,7 +26,7 @@ - + From e8e895cee46305296843819abe1a2b7c71e8c1dd Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Sun, 1 Mar 2026 19:06:35 +0100 Subject: [PATCH 04/21] [IMP] vcp_odoo: add two new menu entries for vcp.odoo.python.library and vcp.odoo.bin.package --- vcp_odoo/__manifest__.py | 2 + vcp_odoo/views/menu.xml | 16 ++++++++ vcp_odoo/views/vcp_odoo_bin_package.xml | 46 ++++++++++++++++++++++ vcp_odoo/views/vcp_odoo_python_library.xml | 46 ++++++++++++++++++++++ 4 files changed, 110 insertions(+) create mode 100644 vcp_odoo/views/vcp_odoo_bin_package.xml create mode 100644 vcp_odoo/views/vcp_odoo_python_library.xml diff --git a/vcp_odoo/__manifest__.py b/vcp_odoo/__manifest__.py index 4270837..db9c82d 100644 --- a/vcp_odoo/__manifest__.py +++ b/vcp_odoo/__manifest__.py @@ -13,6 +13,8 @@ "security/ir.model.access.csv", "views/vcp_odoo_module.xml", "views/vcp_odoo_module_version.xml", + "views/vcp_odoo_bin_package.xml", + "views/vcp_odoo_python_library.xml", "views/vcp_rule.xml", "views/menu.xml", "data/vcp_rule.xml", diff --git a/vcp_odoo/views/menu.xml b/vcp_odoo/views/menu.xml index 4cd05c1..befbdcf 100644 --- a/vcp_odoo/views/menu.xml +++ b/vcp_odoo/views/menu.xml @@ -21,5 +21,21 @@ action="vcp_odoo_module_version_act_window" sequence="20" /> + + + + + + diff --git a/vcp_odoo/views/vcp_odoo_bin_package.xml b/vcp_odoo/views/vcp_odoo_bin_package.xml new file mode 100644 index 0000000..06fc80f --- /dev/null +++ b/vcp_odoo/views/vcp_odoo_bin_package.xml @@ -0,0 +1,46 @@ + + + + + vcp.odoo.bin.package + +
+
+ +
+

+ +

+
+
+ + + + + + vcp.odoo.bin.package + + + + + + + + + vcp.odoo.bin.package + + + + + + + + + Bin Packages + vcp.odoo.bin.package + list,form + [] + {} + + diff --git a/vcp_odoo/views/vcp_odoo_python_library.xml b/vcp_odoo/views/vcp_odoo_python_library.xml new file mode 100644 index 0000000..71e9e01 --- /dev/null +++ b/vcp_odoo/views/vcp_odoo_python_library.xml @@ -0,0 +1,46 @@ + + + + + vcp.odoo.python.library + +
+
+ +
+

+ +

+
+
+ + + + + + vcp.odoo.python.library + + + + + + + + + vcp.odoo.python.library + + + + + + + + + Bin Packages + vcp.odoo.python.library + list,form + [] + {} + + From a8081c4f587f21f1d74a2c9f146878e88882880b Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Sun, 1 Mar 2026 19:30:28 +0100 Subject: [PATCH 05/21] [IMP] vcp_odoo: display on python.library and bin.package form views, the list of odoo.module.version that uses those libs (or bins) --- vcp_odoo/models/vcp_odoo_bin_package.py | 6 ++++++ vcp_odoo/models/vcp_odoo_python_library.py | 6 ++++++ vcp_odoo/views/vcp_odoo_bin_package.xml | 3 +++ vcp_odoo/views/vcp_odoo_python_library.xml | 3 +++ 4 files changed, 18 insertions(+) diff --git a/vcp_odoo/models/vcp_odoo_bin_package.py b/vcp_odoo/models/vcp_odoo_bin_package.py index 5eaf521..3235ddf 100644 --- a/vcp_odoo/models/vcp_odoo_bin_package.py +++ b/vcp_odoo/models/vcp_odoo_bin_package.py @@ -10,6 +10,12 @@ class VcpOdooBinPackage(models.Model): name = fields.Char(required=True, readonly=True) + module_version_ids = fields.Many2many( + "vcp.odoo.module.version", + string="Odoo Module Versions", + readonly=True, + ) + @tools.ormcache("name") def _get_bin_package(self, name): bin_src = self.search([("name", "=", name)], limit=1) diff --git a/vcp_odoo/models/vcp_odoo_python_library.py b/vcp_odoo/models/vcp_odoo_python_library.py index 3031fa1..703f7d4 100644 --- a/vcp_odoo/models/vcp_odoo_python_library.py +++ b/vcp_odoo/models/vcp_odoo_python_library.py @@ -10,6 +10,12 @@ class VcpOdooPythonLibrary(models.Model): name = fields.Char(required=True, readonly=True) + module_version_ids = fields.Many2many( + "vcp.odoo.module.version", + string="Odoo Module Versions", + readonly=True, + ) + @tools.ormcache("name") def _get_python_library(self, name): lib = self.search([("name", "=", name)], limit=1) diff --git a/vcp_odoo/views/vcp_odoo_bin_package.xml b/vcp_odoo/views/vcp_odoo_bin_package.xml index 06fc80f..3c43a0c 100644 --- a/vcp_odoo/views/vcp_odoo_bin_package.xml +++ b/vcp_odoo/views/vcp_odoo_bin_package.xml @@ -13,6 +13,9 @@ + + + diff --git a/vcp_odoo/views/vcp_odoo_python_library.xml b/vcp_odoo/views/vcp_odoo_python_library.xml index 71e9e01..80d9676 100644 --- a/vcp_odoo/views/vcp_odoo_python_library.xml +++ b/vcp_odoo/views/vcp_odoo_python_library.xml @@ -13,6 +13,9 @@ + + + From 7abefa103701c830df65fc86049236ac2fb8f657 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Sun, 1 Mar 2026 21:12:34 +0100 Subject: [PATCH 06/21] [IMP] Allow to unlink modules --- vcp_odoo/models/vcp_odoo_bin_package.py | 13 ++++++++++++- vcp_odoo/models/vcp_odoo_python_library.py | 13 ++++++++++++- vcp_odoo/security/ir.model.access.csv | 8 ++++---- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/vcp_odoo/models/vcp_odoo_bin_package.py b/vcp_odoo/models/vcp_odoo_bin_package.py index 3235ddf..41d7fdf 100644 --- a/vcp_odoo/models/vcp_odoo_bin_package.py +++ b/vcp_odoo/models/vcp_odoo_bin_package.py @@ -1,7 +1,8 @@ # Copyright 2026 Dixmit # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo import fields, models, tools +from odoo import _, api, fields, models, tools +from odoo.exceptions import UserError class VcpOdooBinPackage(models.Model): @@ -22,3 +23,13 @@ def _get_bin_package(self, name): if not bin_src: bin_src = self.create({"name": name}) return bin_src.id + + @api.ondelete(at_uninstall=False) + def _check_module_versions(self): + if self.mapped("module_version_ids"): + raise UserError( + _( + "You can not delete packages that are related to Odoo Modules. " + "You should first delete the related odoo modules." + ) + ) diff --git a/vcp_odoo/models/vcp_odoo_python_library.py b/vcp_odoo/models/vcp_odoo_python_library.py index 703f7d4..d8f01ad 100644 --- a/vcp_odoo/models/vcp_odoo_python_library.py +++ b/vcp_odoo/models/vcp_odoo_python_library.py @@ -1,7 +1,8 @@ # Copyright 2026 Dixmit # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo import fields, models, tools +from odoo import _, api, fields, models, tools +from odoo.exceptions import UserError class VcpOdooPythonLibrary(models.Model): @@ -22,3 +23,13 @@ def _get_python_library(self, name): if not lib: lib = self.create({"name": name}) return lib.id + + @api.ondelete(at_uninstall=False) + def _check_module_versions(self): + if self.mapped("module_version_ids"): + raise UserError( + _( + "You can not delete librairies that are related to Odoo Modules. " + "You should first delete the related odoo modules." + ) + ) diff --git a/vcp_odoo/security/ir.model.access.csv b/vcp_odoo/security/ir.model.access.csv index 0a29ab7..2fe5323 100644 --- a/vcp_odoo/security/ir.model.access.csv +++ b/vcp_odoo/security/ir.model.access.csv @@ -1,9 +1,9 @@ "id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" access_vcp_odoo_module,Access Odoo Module,model_vcp_odoo_module,vcp_management.group_vcp_user,1,0,0,0 -manage_vcp_odoo_module,Manage Odoo Module,model_vcp_odoo_module,vcp_management.group_vcp_manager,1,1,1,0 +manage_vcp_odoo_module,Manage Odoo Module,model_vcp_odoo_module,vcp_management.group_vcp_manager,1,1,1,1 access_vcp_odoo_module_version,Access Odoo Module Version,model_vcp_odoo_module_version,vcp_management.group_vcp_user,1,0,0,0 -manage_vcp_odoo_module_version,Manage Odoo Module Version,model_vcp_odoo_module_version,vcp_management.group_vcp_manager,1,1,1,0 +manage_vcp_odoo_module_version,Manage Odoo Module Version,model_vcp_odoo_module_version,vcp_management.group_vcp_manager,1,1,1,1 access_vcp_odoo_bin_package,Access Odoo Bin Package,model_vcp_odoo_bin_package,vcp_management.group_vcp_user,1,0,0,0 -manage_vcp_odoo_bin_package,Manage Odoo Bin Package,model_vcp_odoo_bin_package,vcp_management.group_vcp_manager,1,1,1,0 +manage_vcp_odoo_bin_package,Manage Odoo Bin Package,model_vcp_odoo_bin_package,vcp_management.group_vcp_manager,1,1,1,1 access_vcp_odoo_python_library,Access Odoo Python Library,model_vcp_odoo_python_library,vcp_management.group_vcp_user,1,0,0,0 -manage_vcp_odoo_python_library,Manage Odoo Python Library,model_vcp_odoo_python_library,vcp_management.group_vcp_manager,1,1,1,0 +manage_vcp_odoo_python_library,Manage Odoo Python Library,model_vcp_odoo_python_library,vcp_management.group_vcp_manager,1,1,1,1 From 53fbb0a5e17b0f937c01897c410c874d35b53422 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Sun, 1 Mar 2026 22:12:58 +0100 Subject: [PATCH 07/21] [IMP] vcp_management: Add a menu entry for the vcp.request.label model. Add a Color field on labels. --- vcp_management/__manifest__.py | 1 + vcp_management/models/__init__.py | 1 + vcp_management/models/vcp_request.py | 18 +------- vcp_management/models/vcp_request_label.py | 27 ++++++++++++ vcp_management/security/ir.model.access.csv | 1 + vcp_management/views/menu.xml | 6 +++ vcp_management/views/vcp_request.xml | 10 +++++ vcp_management/views/vcp_request_label.xml | 47 +++++++++++++++++++++ 8 files changed, 94 insertions(+), 17 deletions(-) create mode 100644 vcp_management/models/vcp_request_label.py create mode 100644 vcp_management/views/vcp_request_label.xml diff --git a/vcp_management/__manifest__.py b/vcp_management/__manifest__.py index ea5f64d..09a1710 100644 --- a/vcp_management/__manifest__.py +++ b/vcp_management/__manifest__.py @@ -17,6 +17,7 @@ "views/vcp_comment.xml", "views/vcp_review.xml", "views/vcp_request.xml", + "views/vcp_request_label.xml", "views/vcp_repository.xml", "views/vcp_branch.xml", "views/vcp_platform.xml", diff --git a/vcp_management/models/__init__.py b/vcp_management/models/__init__.py index be3a675..6d1bd25 100644 --- a/vcp_management/models/__init__.py +++ b/vcp_management/models/__init__.py @@ -7,6 +7,7 @@ from . import vcp_repository from . import vcp_repository_branch from . import vcp_request +from . import vcp_request_label from . import vcp_review from . import vcp_comment from . import res_partner diff --git a/vcp_management/models/vcp_request.py b/vcp_management/models/vcp_request.py index 6f52b75..db998d4 100644 --- a/vcp_management/models/vcp_request.py +++ b/vcp_management/models/vcp_request.py @@ -1,7 +1,7 @@ # Copyright 2026 Dixmit # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo import fields, models, tools +from odoo import fields, models class VcpRequest(models.Model): @@ -62,19 +62,3 @@ class VcpRequest(models.Model): _sql_constraints = [ ("external_id_uniq", "unique(external_id)", "External ID must be unique.") ] - - -class VcpRequestLabel(models.Model): - _name = "vcp.request.label" - _description = "Vcp Request Label" - - name = fields.Char(required=True) - - _sql_constraints = [("name_uniq", "unique(name)", "Label name must be unique.")] - - @tools.ormcache("name") - def _get_label(self, name): - label = self.search([("name", "=", name)], limit=1) - if not label: - label = self.sudo().create({"name": name}) - return label.id diff --git a/vcp_management/models/vcp_request_label.py b/vcp_management/models/vcp_request_label.py new file mode 100644 index 0000000..0a4f8a1 --- /dev/null +++ b/vcp_management/models/vcp_request_label.py @@ -0,0 +1,27 @@ +# Copyright 2026 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from random import randint + +from odoo import fields, models, tools + + +class VcpRequestLabel(models.Model): + _name = "vcp.request.label" + _description = "Vcp Request Label" + + name = fields.Char(required=True, readonly=True) + + color = fields.Char(default=lambda x: x._default_color()) + + _sql_constraints = [("name_uniq", "unique(name)", "Label name must be unique.")] + + def _default_color(self): + return randint(1, 11) + + @tools.ormcache("name") + def _get_label(self, name): + label = self.search([("name", "=", name)], limit=1) + if not label: + label = self.sudo().create({"name": name}) + return label.id diff --git a/vcp_management/security/ir.model.access.csv b/vcp_management/security/ir.model.access.csv index b6a5de5..194ee8a 100644 --- a/vcp_management/security/ir.model.access.csv +++ b/vcp_management/security/ir.model.access.csv @@ -12,6 +12,7 @@ access_rule_information,Access Repository Branch Rule information,model_vcp_rule manage_rule_information,Access Repository Branch Rule information,model_vcp_rule_information,group_vcp_manager,1,1,1,1 access_request,Access Pull Requests,model_vcp_request,group_vcp_user,1,0,0,0 access_request_label,Access Pull Requests Labels,model_vcp_request_label,group_vcp_user,1,0,0,0 +manage_request_label,Access Pull Requests Labels,model_vcp_request_label,group_vcp_manager,1,1,1,1 access_review,Access Reviews,model_vcp_review,group_vcp_user,1,0,0,0 access_comment,Access Comments,model_vcp_comment,group_vcp_user,1,0,0,0 access_vcp_host_type,Access Host Type,model_vcp_host_type,group_vcp_user,1,0,0,0 diff --git a/vcp_management/views/menu.xml b/vcp_management/views/menu.xml index 91d7b02..a99ba1f 100644 --- a/vcp_management/views/menu.xml +++ b/vcp_management/views/menu.xml @@ -48,6 +48,12 @@ action="vcp_review_act_window" sequence="50" /> + diff --git a/vcp_management/views/vcp_request.xml b/vcp_management/views/vcp_request.xml index d2a203a..5d10c8b 100644 --- a/vcp_management/views/vcp_request.xml +++ b/vcp_management/views/vcp_request.xml @@ -24,6 +24,11 @@ + @@ -60,6 +65,11 @@ + diff --git a/vcp_management/views/vcp_request_label.xml b/vcp_management/views/vcp_request_label.xml new file mode 100644 index 0000000..2ba3b29 --- /dev/null +++ b/vcp_management/views/vcp_request_label.xml @@ -0,0 +1,47 @@ + + + + + vcp.request.label + +
+
+ + + + + + + + + + + + vcp.request.label + + + + + + + + + vcp.request.label + + + + + + + + + + Request Labels + vcp.request.label + vcp-request-label + list,form + [] + {} + + From 0b9664d5850432282883e6849cee78eb07f97b9e Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Mon, 2 Mar 2026 00:27:24 +0100 Subject: [PATCH 08/21] [IMP] vcp_management: add link from vcp.request to vcp.review --- vcp_management/models/vcp_request.py | 14 +++++++++++++- vcp_management/models/vcp_review.py | 2 ++ vcp_management/views/vcp_request.xml | 22 ++++++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/vcp_management/models/vcp_request.py b/vcp_management/models/vcp_request.py index db998d4..04775c0 100644 --- a/vcp_management/models/vcp_request.py +++ b/vcp_management/models/vcp_request.py @@ -1,7 +1,7 @@ # Copyright 2026 Dixmit # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo import fields, models +from odoo import api, fields, models class VcpRequest(models.Model): @@ -41,6 +41,13 @@ class VcpRequest(models.Model): related="organization_id.partner_id", string="Organization Partner", ) + review_ids = fields.One2many( + comodel_name="vcp.review", + string="Reviews", + readonly=True, + inverse_name="request_id", + ) + review_count = fields.Integer(compute="_compute_review_count", store=True) url = fields.Char(readonly=True) state = fields.Char(readonly=True) is_merged = fields.Boolean(readonly=True) @@ -62,3 +69,8 @@ class VcpRequest(models.Model): _sql_constraints = [ ("external_id_uniq", "unique(external_id)", "External ID must be unique.") ] + + @api.depends("review_ids") + def _compute_review_count(self): + for record in self: + record.review_count = len(record.review_ids) diff --git a/vcp_management/models/vcp_review.py b/vcp_management/models/vcp_review.py index 4e3f6db..86371dd 100644 --- a/vcp_management/models/vcp_review.py +++ b/vcp_management/models/vcp_review.py @@ -29,6 +29,8 @@ class VcpReview(models.Model): request_id = fields.Many2one( "vcp.request", readonly=True, + required=True, + ondelete="cascade", ) organization_id = fields.Many2one( related="request_id.organization_id", diff --git a/vcp_management/views/vcp_request.xml b/vcp_management/views/vcp_request.xml index 5d10c8b..a26467f 100644 --- a/vcp_management/views/vcp_request.xml +++ b/vcp_management/views/vcp_request.xml @@ -2,12 +2,33 @@ + + Reviews + vcp.review + list,form + [("request_id", "=", active_id)] + + vcp.request
+
+ +
+ From cdd28ffc453e7d9a415f3c6f64a6111390d56f5f Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Mon, 2 Mar 2026 00:46:43 +0100 Subject: [PATCH 09/21] [IMP] vcp_management: add link from vcp.request to vcp.comment --- vcp_management/models/vcp_request.py | 12 ++++++++++++ vcp_management/views/vcp_request.xml | 20 ++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/vcp_management/models/vcp_request.py b/vcp_management/models/vcp_request.py index 04775c0..81322b4 100644 --- a/vcp_management/models/vcp_request.py +++ b/vcp_management/models/vcp_request.py @@ -48,6 +48,13 @@ class VcpRequest(models.Model): inverse_name="request_id", ) review_count = fields.Integer(compute="_compute_review_count", store=True) + comment_ids = fields.One2many( + comodel_name="vcp.comment", + string="Comments", + readonly=True, + inverse_name="request_id", + ) + comment_count = fields.Integer(compute="_compute_comment_count", store=True) url = fields.Char(readonly=True) state = fields.Char(readonly=True) is_merged = fields.Boolean(readonly=True) @@ -74,3 +81,8 @@ class VcpRequest(models.Model): def _compute_review_count(self): for record in self: record.review_count = len(record.review_ids) + + @api.depends("comment_ids") + def _compute_comment_count(self): + for record in self: + record.comment_count = len(record.comment_ids) diff --git a/vcp_management/views/vcp_request.xml b/vcp_management/views/vcp_request.xml index a26467f..06f4a48 100644 --- a/vcp_management/views/vcp_request.xml +++ b/vcp_management/views/vcp_request.xml @@ -9,6 +9,13 @@ [("request_id", "=", active_id)] + + Comments + vcp.comment + list,form + [("request_id", "=", active_id)] + + vcp.request @@ -28,6 +35,18 @@ widget="statinfo" /> + + From 67e00aced742f24b4c8cf13100c9e70f13e5542c Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Mon, 2 Mar 2026 01:22:24 +0100 Subject: [PATCH 10/21] [IMP] vcp_*: get 'draft' state of pull requests. add a new 'status' field on vcp.request, that is based on 'is_draft', 'is_merged' and 'state' field to display the correct ribbon on form view / badge on list view --- vcp_github/models/vcp_repository.py | 1 + vcp_management/models/vcp_request.py | 23 +++++++++++++++++++++++ vcp_management/views/vcp_request.xml | 27 ++++++++++++++++++++++++--- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/vcp_github/models/vcp_repository.py b/vcp_github/models/vcp_repository.py index a44dc09..9f855f7 100644 --- a/vcp_github/models/vcp_repository.py +++ b/vcp_github/models/vcp_repository.py @@ -85,6 +85,7 @@ def _parse_github_pr(self, pr, client): "name": pr.title, "is_merged": any(label["name"] == "merged 🎉" for label in pr.labels) or pr.is_merged(), + "is_draft": pr.draft, "created_at": self.platform_id._parse_github_date( origin_data["created_at"] ), diff --git a/vcp_management/models/vcp_request.py b/vcp_management/models/vcp_request.py index 81322b4..c75c473 100644 --- a/vcp_management/models/vcp_request.py +++ b/vcp_management/models/vcp_request.py @@ -3,6 +3,13 @@ from odoo import api, fields, models +_STATUS_SELECTION = [ + ("draft", "Draft"), + ("open", "Open"), + ("merged", "Merged"), + ("closed", "Closed"), +] + class VcpRequest(models.Model): """ @@ -57,7 +64,11 @@ class VcpRequest(models.Model): comment_count = fields.Integer(compute="_compute_comment_count", store=True) url = fields.Char(readonly=True) state = fields.Char(readonly=True) + status = fields.Selection( + selection=_STATUS_SELECTION, compute="_compute_status", store=True + ) is_merged = fields.Boolean(readonly=True) + is_draft = fields.Boolean(readonly=True) created_at = fields.Datetime(readonly=True) updated_at = fields.Datetime(readonly=True) closed_at = fields.Datetime(readonly=True) @@ -86,3 +97,15 @@ def _compute_review_count(self): def _compute_comment_count(self): for record in self: record.comment_count = len(record.comment_ids) + + @api.depends("is_draft", "is_merged", "state") + def _compute_status(self): + for record in self: + if record.is_merged: + record.status = "merged" + elif record.closed_at: + record.status = "closed" + elif record.is_draft: + record.status = "draft" + else: + record.status = "open" diff --git a/vcp_management/views/vcp_request.xml b/vcp_management/views/vcp_request.xml index 06f4a48..56969ef 100644 --- a/vcp_management/views/vcp_request.xml +++ b/vcp_management/views/vcp_request.xml @@ -48,18 +48,31 @@ /> + + + @@ -110,9 +123,17 @@ widget="many2many_tags" options="{'color_field': 'color'}" /> - + + From b3aae4a8fc8d43d1fdd51fbc392fda8ed68ecaeb Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Mon, 2 Mar 2026 01:56:15 +0100 Subject: [PATCH 11/21] [IMP] vcp_management: allow to delete pull requests --- vcp_management/models/vcp_comment.py | 2 ++ vcp_management/models/vcp_request_label.py | 19 ++++++++++++++++++- vcp_management/security/ir.model.access.csv | 3 +++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/vcp_management/models/vcp_comment.py b/vcp_management/models/vcp_comment.py index 02970b8..938e701 100644 --- a/vcp_management/models/vcp_comment.py +++ b/vcp_management/models/vcp_comment.py @@ -38,6 +38,8 @@ class VcpComment(models.Model): comodel_name="vcp.request", string="Request", readonly=True, + required=True, + ondelete="cascade", ) _sql_constraints = [ ("external_id_uniq", "unique(external_id)", "External ID must be unique.") diff --git a/vcp_management/models/vcp_request_label.py b/vcp_management/models/vcp_request_label.py index 0a4f8a1..5058c16 100644 --- a/vcp_management/models/vcp_request_label.py +++ b/vcp_management/models/vcp_request_label.py @@ -3,7 +3,8 @@ from random import randint -from odoo import fields, models, tools +from odoo import _, api, fields, models, tools +from odoo.exceptions import UserError class VcpRequestLabel(models.Model): @@ -14,6 +15,12 @@ class VcpRequestLabel(models.Model): color = fields.Char(default=lambda x: x._default_color()) + request_ids = fields.Many2many( + comodel_name="vcp.request", + string="Requests", + readonly=True, + ) + _sql_constraints = [("name_uniq", "unique(name)", "Label name must be unique.")] def _default_color(self): @@ -25,3 +32,13 @@ def _get_label(self, name): if not label: label = self.sudo().create({"name": name}) return label.id + + @api.ondelete(at_uninstall=False) + def _check_requests(self): + if self.mapped("request_ids"): + raise UserError( + _( + "You can not delete labels that are related to Requests. " + "You should first delete the related requests." + ) + ) diff --git a/vcp_management/security/ir.model.access.csv b/vcp_management/security/ir.model.access.csv index 194ee8a..b2b35bc 100644 --- a/vcp_management/security/ir.model.access.csv +++ b/vcp_management/security/ir.model.access.csv @@ -11,10 +11,13 @@ manage_repository_branch,Access Repository Branch,model_vcp_repository_branch,gr access_rule_information,Access Repository Branch Rule information,model_vcp_rule_information,group_vcp_user,1,0,0,0 manage_rule_information,Access Repository Branch Rule information,model_vcp_rule_information,group_vcp_manager,1,1,1,1 access_request,Access Pull Requests,model_vcp_request,group_vcp_user,1,0,0,0 +manage_request,Access Pull Requests,model_vcp_request,group_vcp_manager,1,1,1,1 access_request_label,Access Pull Requests Labels,model_vcp_request_label,group_vcp_user,1,0,0,0 manage_request_label,Access Pull Requests Labels,model_vcp_request_label,group_vcp_manager,1,1,1,1 access_review,Access Reviews,model_vcp_review,group_vcp_user,1,0,0,0 +manage_review,Access Reviews,model_vcp_review,group_vcp_manager,1,1,1,1 access_comment,Access Comments,model_vcp_comment,group_vcp_user,1,0,0,0 +manage_comment,Access Comments,model_vcp_comment,group_vcp_manager,1,1,1,1 access_vcp_host_type,Access Host Type,model_vcp_host_type,group_vcp_user,1,0,0,0 access_vcp_host,Access Hosts,model_vcp_host,group_vcp_user,1,0,0,0 manage_vcp_host,Nabage Hosts,model_vcp_host,group_vcp_manager,1,1,1,1 From 69af62c03d97dfc5c16170e67bcd44ec7ee13f38 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Mon, 2 Mar 2026 02:22:16 +0100 Subject: [PATCH 12/21] [IMP] vcp_*: fetch html description --- vcp_odoo/models/vcp_odoo_module_version.py | 1 + vcp_odoo/models/vcp_rule.py | 13 +++++++++++++ vcp_odoo/views/vcp_odoo_module_version.xml | 5 +++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/vcp_odoo/models/vcp_odoo_module_version.py b/vcp_odoo/models/vcp_odoo_module_version.py index 0dbc0c0..eb1b10f 100644 --- a/vcp_odoo/models/vcp_odoo_module_version.py +++ b/vcp_odoo/models/vcp_odoo_module_version.py @@ -45,6 +45,7 @@ class VcpOdooModuleVersion(models.Model): string="Python Binaries", readonly=True, ) + description = fields.Html(readonly=True) def _get_local_path(self): return f"{self.repository_branch_id.local_path}/{self.path}" diff --git a/vcp_odoo/models/vcp_rule.py b/vcp_odoo/models/vcp_rule.py index 8d5f74d..255754f 100644 --- a/vcp_odoo/models/vcp_rule.py +++ b/vcp_odoo/models/vcp_rule.py @@ -5,6 +5,7 @@ import copy import logging import os +from pathlib import Path from odoo import fields, models from odoo.fields import Command @@ -75,6 +76,11 @@ def _get_odoo_icon_path(self): "static/description/icon.png", ] + def _get_html_description_path(self): + return [ + "static/description/index.html", + ] + def _process_rule_odoo_module_prepare_vals( self, repository_branch, module_id, manifest_path ): @@ -100,6 +106,12 @@ def _process_rule_odoo_module_prepare_vals( package_bins.append( self.env["vcp.odoo.bin.package"]._get_bin_package(package_bin) ) + description = False + for html_description_path in self._get_html_description_path(): + path = Path(os.path.dirname(manifest_path)) / html_description_path + if path.exists(): + description = path.read_text() + break return { "name": manifest.get("name"), "module_id": module_id, @@ -118,4 +130,5 @@ def _process_rule_odoo_module_prepare_vals( "image_1920": icon, "python_library_ids": [Command.set(python_libs)], "bin_package_ids": [Command.set(package_bins)], + "description": description, } diff --git a/vcp_odoo/views/vcp_odoo_module_version.xml b/vcp_odoo/views/vcp_odoo_module_version.xml index 8f43e21..a3d27cf 100644 --- a/vcp_odoo/views/vcp_odoo_module_version.xml +++ b/vcp_odoo/views/vcp_odoo_module_version.xml @@ -26,12 +26,13 @@ + - - + + From 56d307076337354d74f6841b7221ebd3921805c5 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Mon, 2 Mar 2026 09:58:24 +0100 Subject: [PATCH 13/21] [IMP] vcp_* : improve naming of field, renaming information_update into scheduled_information_update. Add an helper. Check the field by default, as it is the expected behaviour user want --- vcp_github/demo/demo_vcp_platform.xml | 1 + vcp_github/tests/test_github.py | 2 +- vcp_management/models/vcp_platform.py | 8 ++++++-- vcp_management/tests/test_vcp_crons.py | 6 ++++-- vcp_management/views/vcp_platform.xml | 10 +++++++++- 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/vcp_github/demo/demo_vcp_platform.xml b/vcp_github/demo/demo_vcp_platform.xml index a039cd5..984dc6c 100644 --- a/vcp_github/demo/demo_vcp_platform.xml +++ b/vcp_github/demo/demo_vcp_platform.xml @@ -4,5 +4,6 @@ OCA ^\d+\.\d+$ + diff --git a/vcp_github/tests/test_github.py b/vcp_github/tests/test_github.py index f1d3df4..6e2bb34 100644 --- a/vcp_github/tests/test_github.py +++ b/vcp_github/tests/test_github.py @@ -20,7 +20,7 @@ def setUpClass(cls): Command.create({"name": "ghp_exampletoken1234567890abcdef"}) ], "default_update_repository_information": True, - "information_update": True, + "scheduled_information_update": True, } ) diff --git a/vcp_management/models/vcp_platform.py b/vcp_management/models/vcp_platform.py index 77c6e6d..f72a214 100644 --- a/vcp_management/models/vcp_platform.py +++ b/vcp_management/models/vcp_platform.py @@ -49,7 +49,11 @@ class VcpPlatform(models.Model): ) repository_count = fields.Integer(compute="_compute_repository_count", store=True) default_update_repository_information = fields.Boolean() - information_update = fields.Boolean() + scheduled_information_update = fields.Boolean( + default=True, + help="If checked, the cron that update platform informations" + " will look for up to date information, for this platform.", + ) fetch_repository_fork = fields.Boolean( help="If checked, all repositories will be fetched (sources and forks)." " Otherwise, only sources repositories will be fetched" @@ -98,7 +102,7 @@ def _get_git_url(self, repository): return getattr(self, f"_get_git_url_{self.kind}")(repository) def _cron_update_platforms(self): - for platform in self.search([("information_update", "=", True)]): + for platform in self.search([("scheduled_information_update", "=", True)]): try: platform.update_information() except Exception as e: diff --git a/vcp_management/tests/test_vcp_crons.py b/vcp_management/tests/test_vcp_crons.py index a1d0583..1acd480 100644 --- a/vcp_management/tests/test_vcp_crons.py +++ b/vcp_management/tests/test_vcp_crons.py @@ -32,7 +32,9 @@ def setUpClass(cls): } ) # disable updates to avoid unwanted side effects during tests - cls.env["vcp.platform"].search([]).write({"information_update": False}) + cls.env["vcp.platform"].search([]).write( + {"scheduled_information_update": False} + ) cls.env["vcp.repository"].search([]).write( {"information_update": False, "branch_update": False} ) @@ -43,7 +45,7 @@ def setUpClass(cls): "short_description": "OCA", "description": "OCA", "host_id": cls.host.id, - "information_update": True, + "scheduled_information_update": True, } ) diff --git a/vcp_management/views/vcp_platform.xml b/vcp_management/views/vcp_platform.xml index 4798e72..fe568cc 100644 --- a/vcp_management/views/vcp_platform.xml +++ b/vcp_management/views/vcp_platform.xml @@ -44,7 +44,10 @@ - + @@ -85,6 +88,11 @@ + From d5aabe0a792295879e3aa5906c94c1a0fe8ab860 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Mon, 2 Mar 2026 10:12:12 +0100 Subject: [PATCH 14/21] [REF] vcp_* : harmonize actions. put a path in all actions. rename xml_id of some actions. --- vcp_management/views/vcp_host.xml | 1 + vcp_management/views/vcp_organization.xml | 1 + vcp_management/views/vcp_platform.xml | 10 +++++++++- vcp_management/views/vcp_repository.xml | 20 +++++++++++--------- vcp_management/views/vcp_request.xml | 11 +---------- vcp_management/views/vcp_rule.xml | 1 + vcp_management/views/vcp_user.xml | 1 + vcp_odoo/views/vcp_odoo_bin_package.xml | 1 + vcp_odoo/views/vcp_odoo_module.xml | 1 + vcp_odoo/views/vcp_odoo_module_version.xml | 1 + vcp_odoo/views/vcp_odoo_python_library.xml | 1 + 11 files changed, 29 insertions(+), 20 deletions(-) diff --git a/vcp_management/views/vcp_host.xml b/vcp_management/views/vcp_host.xml index a231261..df18045 100644 --- a/vcp_management/views/vcp_host.xml +++ b/vcp_management/views/vcp_host.xml @@ -41,6 +41,7 @@ Platform Types + vcp-host vcp.host list,form [] diff --git a/vcp_management/views/vcp_organization.xml b/vcp_management/views/vcp_organization.xml index 142a44a..8c09fd8 100644 --- a/vcp_management/views/vcp_organization.xml +++ b/vcp_management/views/vcp_organization.xml @@ -39,6 +39,7 @@ Organizations + vcp-organization vcp.organization list,form [] diff --git a/vcp_management/views/vcp_platform.xml b/vcp_management/views/vcp_platform.xml index fe568cc..79131ed 100644 --- a/vcp_management/views/vcp_platform.xml +++ b/vcp_management/views/vcp_platform.xml @@ -2,6 +2,14 @@ + + Repositories + vcp.repository + vcp-platform-to-repository + list,form + [("platform_id", "=", active_id)] + + vcp.platform @@ -99,7 +107,7 @@ Platforms - vcp-platforms + vcp-platform vcp.platform list,form [] diff --git a/vcp_management/views/vcp_repository.xml b/vcp_management/views/vcp_repository.xml index 75ba13f..cf7f2d5 100644 --- a/vcp_management/views/vcp_repository.xml +++ b/vcp_management/views/vcp_repository.xml @@ -2,6 +2,15 @@ + + Requests + vcp-repository-to-request + vcp.request + list,form + [("repository_id", "=", active_id)] + {} + + vcp.repository @@ -49,7 +58,7 @@ class="oe_stat_button" icon="fa-code-fork fa-flip-vertical" type="action" - name="%(vcp_request_repository_act_window)d" + name="%(vcp_repository_2_request_act_window)d" > - - Repositories - vcp.repository - list,form - [("platform_id", "=", active_id)] - - Repositories - vcp-repositories + vcp-repository vcp.repository list,form [] diff --git a/vcp_management/views/vcp_request.xml b/vcp_management/views/vcp_request.xml index 56969ef..5ef609c 100644 --- a/vcp_management/views/vcp_request.xml +++ b/vcp_management/views/vcp_request.xml @@ -140,19 +140,10 @@ Requests - vcp-requests + vcp-request vcp.request list,form [] {} - - - Requests - vcp-platform-requests - vcp.request - list,form - [("repository_id", "=", active_id)] - {} - diff --git a/vcp_management/views/vcp_rule.xml b/vcp_management/views/vcp_rule.xml index e621272..13cbf2e 100644 --- a/vcp_management/views/vcp_rule.xml +++ b/vcp_management/views/vcp_rule.xml @@ -44,6 +44,7 @@ Processing Rules + vcp-rule vcp.rule list,form [] diff --git a/vcp_management/views/vcp_user.xml b/vcp_management/views/vcp_user.xml index 18e17f9..8d328ad 100644 --- a/vcp_management/views/vcp_user.xml +++ b/vcp_management/views/vcp_user.xml @@ -42,6 +42,7 @@ Users + vcp-user vcp.user list,form [] diff --git a/vcp_odoo/views/vcp_odoo_bin_package.xml b/vcp_odoo/views/vcp_odoo_bin_package.xml index 3c43a0c..ff91bd2 100644 --- a/vcp_odoo/views/vcp_odoo_bin_package.xml +++ b/vcp_odoo/views/vcp_odoo_bin_package.xml @@ -41,6 +41,7 @@ Bin Packages + vcp-odoo-bin-package vcp.odoo.bin.package list,form [] diff --git a/vcp_odoo/views/vcp_odoo_module.xml b/vcp_odoo/views/vcp_odoo_module.xml index 9d47fc6..d7d0166 100644 --- a/vcp_odoo/views/vcp_odoo_module.xml +++ b/vcp_odoo/views/vcp_odoo_module.xml @@ -52,6 +52,7 @@ Modules + vcp-odoo-module vcp.odoo.module list,form [] diff --git a/vcp_odoo/views/vcp_odoo_module_version.xml b/vcp_odoo/views/vcp_odoo_module_version.xml index a3d27cf..3484034 100644 --- a/vcp_odoo/views/vcp_odoo_module_version.xml +++ b/vcp_odoo/views/vcp_odoo_module_version.xml @@ -68,6 +68,7 @@ Module Versions + vcp-odoo-module-version vcp.odoo.module.version list,form [] diff --git a/vcp_odoo/views/vcp_odoo_python_library.xml b/vcp_odoo/views/vcp_odoo_python_library.xml index 80d9676..0b5580c 100644 --- a/vcp_odoo/views/vcp_odoo_python_library.xml +++ b/vcp_odoo/views/vcp_odoo_python_library.xml @@ -41,6 +41,7 @@ Bin Packages + vcp-odoo-python-library vcp.odoo.python.library list,form [] From 54d2275085065b9ca3ac8b83c93f12f8da695336 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Mon, 2 Mar 2026 11:01:54 +0100 Subject: [PATCH 15/21] [IMP] vcp_* : improve naming of field, renaming information_update into scheduled_information_update for vcp.repository model. Add helpers. explicit limit in cron python code. --- vcp_github/tests/test_github.py | 2 +- vcp_management/data/ir_cron.xml | 2 +- vcp_management/models/vcp_platform.py | 5 ++++- vcp_management/models/vcp_repository.py | 19 ++++++++++++------- vcp_management/tests/test_vcp_crons.py | 6 +++--- vcp_management/views/vcp_platform.xml | 5 ++++- vcp_management/views/vcp_repository.xml | 10 +++++++++- 7 files changed, 34 insertions(+), 15 deletions(-) diff --git a/vcp_github/tests/test_github.py b/vcp_github/tests/test_github.py index 6e2bb34..e598de7 100644 --- a/vcp_github/tests/test_github.py +++ b/vcp_github/tests/test_github.py @@ -19,7 +19,7 @@ def setUpClass(cls): "key_ids": [ Command.create({"name": "ghp_exampletoken1234567890abcdef"}) ], - "default_update_repository_information": True, + "default_repository_scheduled_information_update": True, "scheduled_information_update": True, } ) diff --git a/vcp_management/data/ir_cron.xml b/vcp_management/data/ir_cron.xml index bb3ba1c..27dff7f 100644 --- a/vcp_management/data/ir_cron.xml +++ b/vcp_management/data/ir_cron.xml @@ -6,7 +6,7 @@ VCP: Repository Update code - model._cron_update_repositories() + model._cron_update_repositories(limit=1) 1 minutes False diff --git a/vcp_management/models/vcp_platform.py b/vcp_management/models/vcp_platform.py index f72a214..48d116e 100644 --- a/vcp_management/models/vcp_platform.py +++ b/vcp_management/models/vcp_platform.py @@ -48,7 +48,10 @@ class VcpPlatform(models.Model): inverse_name="platform_id", ) repository_count = fields.Integer(compute="_compute_repository_count", store=True) - default_update_repository_information = fields.Boolean() + default_repository_scheduled_information_update = fields.Boolean( + help="If checked, the cron that update repositories" + " will look for up to date information, for this repository.", + ) scheduled_information_update = fields.Boolean( default=True, help="If checked, the cron that update platform informations" diff --git a/vcp_management/models/vcp_repository.py b/vcp_management/models/vcp_repository.py index 665ef56..7404538 100644 --- a/vcp_management/models/vcp_repository.py +++ b/vcp_management/models/vcp_repository.py @@ -36,10 +36,13 @@ class VcpRepository(models.Model): request_count = fields.Integer(compute="_compute_request_count") test_field = fields.Char() # TODO remove after testing active = fields.Boolean(default=True, readonly=True) - information_update = fields.Boolean( - compute="_compute_information_update", + scheduled_information_update = fields.Boolean( + compute="_compute_scheduled_information_update", store=True, readonly=False, + help="If checked, the cron that update repository informations" + " will look for up to date information, for this repository." + " This update include the recovery of requests, comments and reviews.", ) branch_update = fields.Boolean(default=False) branch_update_date = fields.Datetime( @@ -73,10 +76,10 @@ def _get_git_url(self): return self.platform_id._get_git_url(self) @api.depends("platform_id") - def _compute_information_update(self): + def _compute_scheduled_information_update(self): for record in self: - record.information_update = ( - record.platform_id.default_update_repository_information + record.scheduled_information_update = ( + record.platform_id.default_repository_scheduled_information_update ) @api.depends("request_ids") @@ -104,9 +107,11 @@ def update_information(self, update_interval_days=None): update_interval_days=update_interval_days ) - def _cron_update_repositories(self, limit=1): + def _cron_update_repositories(self, limit): repositories = self.search( - [("information_update", "=", True)], limit=limit, order="from_date ASC" + [("scheduled_information_update", "=", True)], + limit=limit, + order="from_date ASC", ) for repository in repositories: repository.update_information() diff --git a/vcp_management/tests/test_vcp_crons.py b/vcp_management/tests/test_vcp_crons.py index 1acd480..78298f4 100644 --- a/vcp_management/tests/test_vcp_crons.py +++ b/vcp_management/tests/test_vcp_crons.py @@ -36,7 +36,7 @@ def setUpClass(cls): {"scheduled_information_update": False} ) cls.env["vcp.repository"].search([]).write( - {"information_update": False, "branch_update": False} + {"scheduled_information_update": False, "branch_update": False} ) # be sure some expected values are set otherwise homepage may fail cls.platform = cls.env["vcp.platform"].create( @@ -55,7 +55,7 @@ def test_repository_update_no_definition(self): "name": "test_repo", "description": "Test Repository", "platform_id": self.platform.id, - "information_update": True, + "scheduled_information_update": True, "from_date": Date.today(), } ) @@ -97,7 +97,7 @@ def dummy_update_information(oself, *args, **kwargs): "name": "test_repo", "description": "Test Repository", "platform_id": oself.id, - "information_update": True, + "scheduled_information_update": True, "branch_update": True, "from_date": Date.today(), } diff --git a/vcp_management/views/vcp_platform.xml b/vcp_management/views/vcp_platform.xml index 79131ed..f930a10 100644 --- a/vcp_management/views/vcp_platform.xml +++ b/vcp_management/views/vcp_platform.xml @@ -56,7 +56,10 @@ name="scheduled_information_update" widget="boolean_toggle" /> - + diff --git a/vcp_management/views/vcp_repository.xml b/vcp_management/views/vcp_repository.xml index cf7f2d5..d8b89d0 100644 --- a/vcp_management/views/vcp_repository.xml +++ b/vcp_management/views/vcp_repository.xml @@ -80,7 +80,10 @@ - + @@ -138,6 +141,11 @@ + From 75e9fb8d6066f94ef61ca89b68e5e35ef66de96a Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Mon, 2 Mar 2026 11:11:28 +0100 Subject: [PATCH 16/21] [IMP] vcp_* : improve naming of field, renaming branch_update into scheduled_branch_update for vcp.repository model. Add helpers. explicit limit in cron python code. --- vcp_management/data/ir_cron.xml | 2 +- vcp_management/models/vcp_platform.py | 4 ++++ vcp_management/models/vcp_repository.py | 21 ++++++++++++++++++--- vcp_management/tests/test_vcp_crons.py | 6 +++--- vcp_management/views/vcp_platform.xml | 4 ++++ vcp_management/views/vcp_repository.xml | 7 ++++++- 6 files changed, 36 insertions(+), 8 deletions(-) diff --git a/vcp_management/data/ir_cron.xml b/vcp_management/data/ir_cron.xml index 27dff7f..bcf8e82 100644 --- a/vcp_management/data/ir_cron.xml +++ b/vcp_management/data/ir_cron.xml @@ -24,7 +24,7 @@ VCP: Branch Update code - model._cron_update_branches() + model._cron_update_branches(limit=1) 1 days False diff --git a/vcp_management/models/vcp_platform.py b/vcp_management/models/vcp_platform.py index 48d116e..23b025c 100644 --- a/vcp_management/models/vcp_platform.py +++ b/vcp_management/models/vcp_platform.py @@ -52,6 +52,10 @@ class VcpPlatform(models.Model): help="If checked, the cron that update repositories" " will look for up to date information, for this repository.", ) + default_repository_scheduled_branch_update = fields.Boolean( + help="If checked, the cron that update repository branches" + " will look for up to date branches, for this repository.", + ) scheduled_information_update = fields.Boolean( default=True, help="If checked, the cron that update platform informations" diff --git a/vcp_management/models/vcp_repository.py b/vcp_management/models/vcp_repository.py index 7404538..5debe42 100644 --- a/vcp_management/models/vcp_repository.py +++ b/vcp_management/models/vcp_repository.py @@ -44,7 +44,13 @@ class VcpRepository(models.Model): " will look for up to date information, for this repository." " This update include the recovery of requests, comments and reviews.", ) - branch_update = fields.Boolean(default=False) + scheduled_branch_update = fields.Boolean( + compute="_compute_scheduled_branch_update", + store=True, + readonly=False, + help="If checked, the cron that update repository branches" + " will look for up to date branches, for this repository.", + ) branch_update_date = fields.Datetime( readonly=True, required=True, default=fields.Datetime.now ) @@ -82,6 +88,13 @@ def _compute_scheduled_information_update(self): record.platform_id.default_repository_scheduled_information_update ) + @api.depends("platform_id") + def _compute_scheduled_branch_update(self): + for record in self: + record.scheduled_branch_update = ( + record.platform_id.default_repository_scheduled_branch_update + ) + @api.depends("request_ids") def _compute_request_count(self): for record in self: @@ -116,9 +129,11 @@ def _cron_update_repositories(self, limit): for repository in repositories: repository.update_information() - def _cron_update_branches(self, limit=1): + def _cron_update_branches(self, limit): repositories = self.search( - [("branch_update", "=", True)], limit=limit, order="branch_update_date ASC" + [("scheduled_branch_update", "=", True)], + limit=limit, + order="branch_update_date ASC", ) for repository in repositories: repository.update_branches() diff --git a/vcp_management/tests/test_vcp_crons.py b/vcp_management/tests/test_vcp_crons.py index 78298f4..2294420 100644 --- a/vcp_management/tests/test_vcp_crons.py +++ b/vcp_management/tests/test_vcp_crons.py @@ -36,7 +36,7 @@ def setUpClass(cls): {"scheduled_information_update": False} ) cls.env["vcp.repository"].search([]).write( - {"scheduled_information_update": False, "branch_update": False} + {"scheduled_information_update": False, "scheduled_branch_update": False} ) # be sure some expected values are set otherwise homepage may fail cls.platform = cls.env["vcp.platform"].create( @@ -71,7 +71,7 @@ def test_platform_branch_update_no_definition(self): "name": "test_repo", "description": "Test Repository", "platform_id": self.platform.id, - "branch_update": True, + "scheduled_branch_update": True, "from_date": Date.today(), } ) @@ -98,7 +98,7 @@ def dummy_update_information(oself, *args, **kwargs): "description": "Test Repository", "platform_id": oself.id, "scheduled_information_update": True, - "branch_update": True, + "scheduled_branch_update": True, "from_date": Date.today(), } ) diff --git a/vcp_management/views/vcp_platform.xml b/vcp_management/views/vcp_platform.xml index f930a10..328c3de 100644 --- a/vcp_management/views/vcp_platform.xml +++ b/vcp_management/views/vcp_platform.xml @@ -60,6 +60,10 @@ name="default_repository_scheduled_information_update" widget="boolean_toggle" /> + diff --git a/vcp_management/views/vcp_repository.xml b/vcp_management/views/vcp_repository.xml index d8b89d0..ca97fe4 100644 --- a/vcp_management/views/vcp_repository.xml +++ b/vcp_management/views/vcp_repository.xml @@ -84,7 +84,7 @@ name="scheduled_information_update" widget="boolean_toggle" /> - + @@ -146,6 +146,11 @@ widget="boolean_toggle" optional="hide" /> + From befb1ed876adcdca6b0529a59d28200983bdc6de Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Mon, 2 Mar 2026 11:14:29 +0100 Subject: [PATCH 17/21] [IMP] vcp_management: explicit limit in dron definition. --- vcp_management/data/ir_cron.xml | 2 +- vcp_management/models/vcp_repository_branch.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vcp_management/data/ir_cron.xml b/vcp_management/data/ir_cron.xml index bcf8e82..7746dda 100644 --- a/vcp_management/data/ir_cron.xml +++ b/vcp_management/data/ir_cron.xml @@ -33,7 +33,7 @@ VCP: Branch Rule Process code - model._cron_process_branch_rules() + model._cron_process_branch_rules(limit=10) 1 days False diff --git a/vcp_management/models/vcp_repository_branch.py b/vcp_management/models/vcp_repository_branch.py index 88f5407..0bb5e50 100644 --- a/vcp_management/models/vcp_repository_branch.py +++ b/vcp_management/models/vcp_repository_branch.py @@ -40,7 +40,7 @@ class VcpRepositoryBranch(models.Model): required=True, ) - def _cron_process_branch_rules(self, limit=10): + def _cron_process_branch_rules(self, limit): branches = self.search([], limit=limit, order="update_rule_processing_date asc") for branch in branches: branch.process_rules() From d465f9defb7bc122ce3cbe146c8d9fe9f33fb932 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Mon, 2 Mar 2026 11:25:02 +0100 Subject: [PATCH 18/21] [IMP] vcp_management: add a filter to display only active requests. (draft and open) --- vcp_management/views/vcp_repository.xml | 2 +- vcp_management/views/vcp_request.xml | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/vcp_management/views/vcp_repository.xml b/vcp_management/views/vcp_repository.xml index ca97fe4..22c3ac5 100644 --- a/vcp_management/views/vcp_repository.xml +++ b/vcp_management/views/vcp_repository.xml @@ -8,7 +8,7 @@ vcp.request list,form [("repository_id", "=", active_id)] - {} + {'search_default_filter_active': 1} diff --git a/vcp_management/views/vcp_request.xml b/vcp_management/views/vcp_request.xml index 5ef609c..1f166b2 100644 --- a/vcp_management/views/vcp_request.xml +++ b/vcp_management/views/vcp_request.xml @@ -90,6 +90,7 @@ +
@@ -105,6 +106,11 @@ + @@ -112,12 +118,13 @@ vcp.request - + + vcp.request list,form [] - {} + {'search_default_filter_active': 1} From 51a93d8c214852cbacda1742e65f5430506c8bb4 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Mon, 2 Mar 2026 12:06:32 +0100 Subject: [PATCH 19/21] [IMP] vpc_management: add vcp.repository.branch menu entry --- vcp_management/__manifest__.py | 1 + .../models/vcp_repository_branch.py | 2 + vcp_management/views/menu.xml | 6 ++ vcp_management/views/vcp_repository.xml | 26 --------- .../views/vcp_repository_branch.xml | 58 +++++++++++++++++++ 5 files changed, 67 insertions(+), 26 deletions(-) create mode 100644 vcp_management/views/vcp_repository_branch.xml diff --git a/vcp_management/__manifest__.py b/vcp_management/__manifest__.py index 09a1710..666ca84 100644 --- a/vcp_management/__manifest__.py +++ b/vcp_management/__manifest__.py @@ -19,6 +19,7 @@ "views/vcp_request.xml", "views/vcp_request_label.xml", "views/vcp_repository.xml", + "views/vcp_repository_branch.xml", "views/vcp_branch.xml", "views/vcp_platform.xml", "views/vcp_organization.xml", diff --git a/vcp_management/models/vcp_repository_branch.py b/vcp_management/models/vcp_repository_branch.py index 0bb5e50..df80536 100644 --- a/vcp_management/models/vcp_repository_branch.py +++ b/vcp_management/models/vcp_repository_branch.py @@ -18,11 +18,13 @@ class VcpRepositoryBranch(models.Model): "vcp.branch", string="Branch", required=True, + readonly=True, ondelete="cascade", ) repository_id = fields.Many2one( "vcp.repository", required=True, + readonly=True, ondelete="cascade", ) platform_id = fields.Many2one( diff --git a/vcp_management/views/menu.xml b/vcp_management/views/menu.xml index a99ba1f..19f03c4 100644 --- a/vcp_management/views/menu.xml +++ b/vcp_management/views/menu.xml @@ -36,6 +36,12 @@ action="vcp_branch_act_window" sequence="10" /> + - - vcp.repository.branch - -
- - - - - - - - - - - - - - - -
-
-
- Repositories vcp-repository diff --git a/vcp_management/views/vcp_repository_branch.xml b/vcp_management/views/vcp_repository_branch.xml new file mode 100644 index 0000000..3bbd321 --- /dev/null +++ b/vcp_management/views/vcp_repository_branch.xml @@ -0,0 +1,58 @@ + + + + + vcp.repository.branch + +
+ + + + + + + + + + + + + + + +
+
+
+ + + vcp.repository.branch + + + + + + + + + + + vcp.repository.branch + + + + + + + + + + + Repository Branches + vcp-repository-branch + vcp.repository.branch + list,form + [] + {} + +
From d6aa04160a3ecb061ddf61b9acae0bf9cc762865 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Mon, 2 Mar 2026 12:30:55 +0100 Subject: [PATCH 20/21] [FIX] vcp_github: do not create a branch when fetching pull request, if the target branch doesn't match the pattern --- vcp_github/models/vcp_repository.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/vcp_github/models/vcp_repository.py b/vcp_github/models/vcp_repository.py index 9f855f7..016e5e9 100644 --- a/vcp_github/models/vcp_repository.py +++ b/vcp_github/models/vcp_repository.py @@ -56,6 +56,7 @@ def _update_branches_github(self): raise ValidationError(self.env._(f"Reset on {reset}")) from e def _parse_github_pr(self, pr, client): + self.ensure_one() origin_data = pr.as_dict() comments_url = pr.comments_url comments_req = client.session.get(comments_url) @@ -71,12 +72,22 @@ def _parse_github_pr(self, pr, client): reviews_url = reviews_req.links["next"]["url"] reviews_req = client.session.get(reviews_url) reviews += reviews_req.json() + + branch_pattern = ( + self.fetch_branch_pattern + or self.platform_id.fetch_repository_branch_pattern + or False + ) + if branch_pattern and not re.match(branch_pattern, pr.base.ref): + branch_id = False + else: + branch_id = self.platform_id._get_branch(pr.base.ref) return ( str(pr.id), { "user_id": self.platform_id.host_id._get_user(pr.user.login), "repository_id": self.id, - "branch_id": self.platform_id._get_branch(pr.base.ref), + "branch_id": branch_id, "organization_id": self.platform_id.host_id._get_organization( pr.head.repo[0] ), From 3520a5a6f2f552ef9fd73f520061a5990288cb37 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Mon, 2 Mar 2026 14:22:27 +0100 Subject: [PATCH 21/21] [FIX] vcp_management: tests now include parameter limit --- vcp_management/tests/test_vcp_crons.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vcp_management/tests/test_vcp_crons.py b/vcp_management/tests/test_vcp_crons.py index 2294420..f24a514 100644 --- a/vcp_management/tests/test_vcp_crons.py +++ b/vcp_management/tests/test_vcp_crons.py @@ -79,7 +79,7 @@ def test_platform_branch_update_no_definition(self): self.assertRaises(AttributeError), mute_logger("odoo.addons.vcp_management.models.vcp_platform"), ): - self.env["vcp.repository"]._cron_update_branches() + self.env["vcp.repository"]._cron_update_branches(limit=1) def test_platform_update_no_definition(self): with ( @@ -142,7 +142,7 @@ def dummy_repository_update_information(oself, *args, **kwargs): dummy_repository_update_information, create=True, ): - self.env["vcp.repository"]._cron_update_repositories() + self.env["vcp.repository"]._cron_update_repositories(limit=1) repository.invalidate_recordset() self.assertTrue(repository.request_ids) self.assertFalse(repository.branch_ids) @@ -162,7 +162,7 @@ def dummy_repository_update_branches(oself, *args, **kwargs): dummy_repository_update_branches, create=True, ): - self.env["vcp.repository"]._cron_update_branches() + self.env["vcp.repository"]._cron_update_branches(limit=1) self.assertTrue(repository.branch_ids) self.assertEqual(repository.branch_ids.branch_id.name, "main")