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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 30 additions & 4 deletions odoo_repository/lib/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@

import git
import oca_port
from odoo_addons_parser import ModuleParser
from odoo_addons_parser import ModuleParser, OdooParser
from odoo_addons_parser.odoo import ODOO_BASE_ADDONS_PATH

# Disable logging from 'pygount' (used by odoo_addons_parser)
logging.getLogger("pygount").setLevel(logging.ERROR)
Expand Down Expand Up @@ -923,6 +924,7 @@ def __init__(
token: str = None,
workaround_fs_errors: bool = False,
clone_name: str = None,
parse_code: bool = False,
):
super().__init__(
org,
Expand All @@ -939,6 +941,7 @@ def __init__(
self.version = version
self.branch = branch
self.addons_paths_data = addons_paths_data
self.parse_code = parse_code

def detect_modules_to_scan(self):
res = self.sync()
Expand Down Expand Up @@ -1111,9 +1114,32 @@ def _run_module_code_analysis(
self, repo, module_path, branch, from_commit, to_commit
):
"""Perform a code analysis of `module_path`."""
# Get current code analysis data
parser = ModuleParser(f"{self.path}/{module_path}", scan_models=False)
data = parser.to_dict()
module = pathlib.Path(module_path).parts[-1]
# When scanning 'base' module, we want to include framework base models
# in it as well (AbstractModel, Model...) to ease the data exploration
# afterwards.
if self.parse_code and module == "base":
parser = OdooParser(
self.path,
scan_models=self.parse_code,
# No addons path provided to scan only framework code
# Put ODOO_BASE_ADDONS_PATH to avoid the merge of modules data
# with results of two parsers.
# This will also scan other modules (mainly Odoo test modules) but
# it's fine.
addons_paths=(ODOO_BASE_ADDONS_PATH,),
base_models_key=module,
)
data = parser.to_dict()[module]
else:
# Get current code analysis data
full_module_path = self.path.joinpath(module_path)
parser = ModuleParser(
full_module_path,
scan_models=self.parse_code,
scan_data=self.parse_code,
)
data = parser.to_dict()
# Append the history of versions
versions = self._read_module_versions(
repo, module_path, branch, from_commit, to_commit
Expand Down
35 changes: 10 additions & 25 deletions odoo_repository/tests/odoo_repo_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@

cache = threading.local()

# Real Odoo module (located in 'tests/samples/') copied into the fixture Git
# repository, and scanned by the tests
FIXTURE_MODULE_PATH = Path(__file__).parent / "samples" / "my_module"


class OdooRepoMixin(unittest.TestCase):
@classmethod
Expand Down Expand Up @@ -124,31 +128,12 @@ def _fill_git_repository(cls, repo_path: Path, addon_path: Path):

@classmethod
def _create_module(cls, module_path: Path):
manifest_lines = [
"# Copyright 2026 Sébastien Alix\n",
"# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)\n",
"{\n",
' "name": "Test",\n',
' "version": "1.0.0",\n',
' "category": "Test Module",\n',
' "author": "Odoo Community Association (OCA)",\n',
' "website": "https://github.com/OCA/module-composition-analysis",\n',
' "license": "AGPL-3",\n',
' "depends": ["base"],\n',
' "data": [],\n',
' "demo": [],\n',
' "installable": True,\n',
"}\n",
]
module_path.mkdir(parents=True, exist_ok=True)
manifest_path = module_path / "__manifest__.py"
with open(manifest_path, "w") as manifest:
manifest.writelines(manifest_lines)
# Add a file which should not be checked out with sparse checkout
icon_path = module_path / "static" / "description" / "icon.png"
icon_path.parent.mkdir(parents=True, exist_ok=True)
with open(icon_path, "wb") as icon:
icon.write(b"fake icon data")
shutil.copytree(
FIXTURE_MODULE_PATH,
module_path,
dirs_exist_ok=True,
ignore=shutil.ignore_patterns("__pycache__", "*.py[cod]"),
)

@classmethod
def tearDownClass(cls):
Expand Down
20 changes: 20 additions & 0 deletions odoo_repository/tests/samples/my_module/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2026 Sébastien Alix
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)

{
"name": "Test",
"version": "1.0.0",
"category": "Test Module",
"author": "Odoo Community Association (OCA)",
"website": "https://github.com/OCA/module-composition-analysis",
"license": "AGPL-3",
"depends": ["base"],
"data": [
"security/ir.model.access.csv",
"views/my_model.xml",
],
"demo": [
"demo/my_model.xml",
],
"installable": True,
}
8 changes: 8 additions & 0 deletions odoo_repository/tests/samples/my_module/demo/my_model.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data noupdate="1">
<record id="my_model_demo" model="my_module.my_model">
<field name="name">Demo</field>
</record>
</data>
</odoo>
2 changes: 2 additions & 0 deletions odoo_repository/tests/samples/my_module/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import my_model
from . import res_partner
14 changes: 14 additions & 0 deletions odoo_repository/tests/samples/my_module/models/my_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright 2026 Sébastien Alix
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)

from odoo import fields, models


class MyModel(models.Model):
_name = "my_module.my_model"
_description = "My Model"

name = fields.Char()

def my_method(self):
return True
10 changes: 10 additions & 0 deletions odoo_repository/tests/samples/my_module/models/res_partner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright 2026 Sébastien Alix
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)

from odoo import fields, models


class ResPartner(models.Model):
_inherit = "res.partner"

my_field = fields.Char()
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_my_module_my_model,access.my_module.my_model,model_my_module_my_model,base.group_user,1,1,0,0
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions odoo_repository/tests/samples/my_module/views/my_model.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2026 Sébastien Alix
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) -->
<odoo>
<record id="my_model_view_form" model="ir.ui.view">
<field name="name">my_module.my_model.form</field>
<field name="model">my_module.my_model</field>
<field name="arch" type="xml">
<form>
<field name="name" />
</form>
</field>
</record>
<menuitem
id="my_model_menu"
name="My Model"
/>
</odoo>
84 changes: 84 additions & 0 deletions odoo_repository_code/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
====================
Odoo Repository Code
====================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:359273ec7d389c3dd991ea041c8277187c0af57b041d284ae6ac681670b6688c
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |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-OCA%2Fmodule--composition--analysis-lightgray.png?logo=github
:target: https://github.com/OCA/module-composition-analysis/tree/18.0/odoo_repository_code
:alt: OCA/module-composition-analysis
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/module-composition-analysis-18-0/module-composition-analysis-18-0-odoo_repository_code
: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/module-composition-analysis&target_branch=18.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This modules extends ``odoo_repository`` to also collect coding elements
from Odoo modules.

It will collect the following:

- Odoo models
- Fields
- Methods with their signature and body
- Data records from XML and CSV files

**Table of contents**

.. contents::
:local:

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/module-composition-analysis/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 <https://github.com/OCA/module-composition-analysis/issues/new?body=module:%20odoo_repository_code%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

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

Credits
=======

Authors
-------

* sebalix

Contributors
------------

- Sébastien Alix <seb@usr-src.org>

Maintainers
-----------

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/module-composition-analysis <https://github.com/OCA/module-composition-analysis/tree/18.0/odoo_repository_code>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions odoo_repository_code/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
25 changes: 25 additions & 0 deletions odoo_repository_code/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright 2025 Sebastien Alix <https://github.com/sebalix>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "Odoo Repository Code",
"summary": "Collect modules coding elements from Odoo Repositories.",
"version": "18.0.1.0.0",
"category": "Tools",
"author": "sebalix, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/module-composition-analysis",
"data": [
"security/ir.model.access.csv",
"views/menu.xml",
"views/odoo_model_version.xml",
"views/odoo_module_branch_model.xml",
"views/odoo_module_branch_model_field.xml",
"views/odoo_module_branch_model_method.xml",
"views/odoo_module_branch_data.xml",
"views/odoo_module_branch.xml",
],
"installable": True,
"depends": [
"odoo_repository",
],
"license": "AGPL-3",
}
9 changes: 9 additions & 0 deletions odoo_repository_code/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from . import odoo_repository
from . import odoo_model
from . import odoo_model_version
from . import odoo_module_branch
from . import odoo_module_branch_model
from . import odoo_module_branch_model_resource_mixin
from . import odoo_module_branch_model_field
from . import odoo_module_branch_model_method
from . import odoo_module_branch_data
11 changes: 11 additions & 0 deletions odoo_repository_code/models/odoo_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright 2025 Sebastien Alix <https://github.com/sebalix>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import fields, models


class OdooModel(models.Model):
_name = "odoo.model"
_description = "Odoo Model Technical Name"

name = fields.Char(required=True, index=True)
35 changes: 35 additions & 0 deletions odoo_repository_code/models/odoo_model_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Copyright 2025 Sebastien Alix <https://github.com/sebalix>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import api, fields, models


class OdooModelVersion(models.Model):
_name = "odoo.model.version"
_description = "Odoo Model Technical Name for Odoo Version"

odoo_model_id = fields.Many2one(
comodel_name="odoo.model",
ondelete="cascade",
string="Odoo Model",
required=True,
index=True,
)
odoo_version_id = fields.Many2one(
comodel_name="odoo.branch",
ondelete="restrict",
string="Odoo Version",
required=True,
index=True,
)
name = fields.Char(compute="_compute_name", store=True)
module_branch_model_ids = fields.One2many(
comodel_name="odoo.module.branch.model",
inverse_name="odoo_model_version_id",
string="Models",
)

@api.depends("odoo_model_id", "odoo_version_id")
def _compute_name(self):
for rec in self:
rec.name = f"[{rec.odoo_version_id.name}] {rec.odoo_model_id.name}"
Loading
Loading