[IMP] module_analysis: black, isort, prettier

pull/2608/head
Telmo Santos 2021-01-06 15:19:29 +01:00 committed by Florian da Costa
parent 2e88c5b31e
commit 8fc7d87806
19 changed files with 242 additions and 260 deletions

View File

@ -1,2 +1,2 @@
from . import models from . import models
from . post_init_hook import analyse_installed_modules from .post_init_hook import analyse_installed_modules

View File

@ -3,32 +3,28 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{ {
'name': "Module Analysis", "name": "Module Analysis",
'summary': "Add analysis tools regarding installed modules" "summary": "Add analysis tools regarding installed modules"
" to know which installed modules comes from Odoo Core, OCA, or are" " to know which installed modules comes from Odoo Core, OCA, or are"
" custom modules", " custom modules",
'author': 'GRAP, Odoo Community Association (OCA)', "author": "GRAP, Odoo Community Association (OCA)",
'website': "https://github.com/OCA/server-tools/", "website": "https://github.com/OCA/server-tools/",
'version': '12.0.1.0.0', "version": "12.0.1.0.0",
'license': 'AGPL-3', "license": "AGPL-3",
'depends': [ "depends": ["base",],
'base', "data": [
"security/ir.model.access.csv",
"views/menu.xml",
"views/view_base_module_update.xml",
"views/view_ir_module_author.xml",
"views/view_ir_module_type.xml",
"views/view_ir_module_type_rule.xml",
"views/view_ir_module_module.xml",
"data/ir_config_parameter.xml",
"data/ir_module_type.xml",
"data/ir_module_type_rule.xml",
], ],
'data': [ "external_dependencies": {"python": ["pygount"],},
'security/ir.model.access.csv', "post_init_hook": "analyse_installed_modules",
'views/menu.xml', "installable": True,
'views/view_base_module_update.xml',
'views/view_ir_module_author.xml',
'views/view_ir_module_type.xml',
'views/view_ir_module_type_rule.xml',
'views/view_ir_module_module.xml',
'data/ir_config_parameter.xml',
'data/ir_module_type.xml',
'data/ir_module_type_rule.xml',
],
'external_dependencies': {
'python': ['pygount'],
},
'post_init_hook': 'analyse_installed_modules',
'installable': True,
} }

View File

@ -1,20 +1,16 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- <!--
Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>) Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain) @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
--> -->
<odoo noupdate="1"> <odoo noupdate="1">
<record id="parameter_exclude_directories" model="ir.config_parameter"> <record id="parameter_exclude_directories" model="ir.config_parameter">
<field name="key">module_analysis.exclude_directories</field> <field name="key">module_analysis.exclude_directories</field>
<field name="value">lib,demo,test,tests,doc,description</field> <field name="value">lib,demo,test,tests,doc,description</field>
</record> </record>
<record id="parameter_exclude_files" model="ir.config_parameter"> <record id="parameter_exclude_files" model="ir.config_parameter">
<field name="key">module_analysis.exclude_files</field> <field name="key">module_analysis.exclude_files</field>
<field name="value">__openerp__.py,__manifest__.py</field> <field name="value">__openerp__.py,__manifest__.py</field>
</record> </record>
</odoo> </odoo>

View File

@ -1,18 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- <!--
Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>) Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain) @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
--> -->
<odoo> <odoo>
<record id="module_type_odoo" model="ir.module.type"> <record id="module_type_odoo" model="ir.module.type">
<field name="name">Odoo Core</field> <field name="name">Odoo Core</field>
</record> </record>
<record id="module_type_oca" model="ir.module.type"> <record id="module_type_oca" model="ir.module.type">
<field name="name">OCA</field> <field name="name">OCA</field>
</record> </record>
</odoo> </odoo>

View File

@ -1,42 +1,37 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- <!--
Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>) Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain) @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
--> -->
<odoo> <odoo>
<!-- Odoo Rules --> <!-- Odoo Rules -->
<record id="module_type_rule_odoo_a" model="ir.module.type.rule"> <record id="module_type_rule_odoo_a" model="ir.module.type.rule">
<field name="sequence">1</field> <field name="sequence">1</field>
<field name="module_domain">[('author_ids', 'ilike', 'Odoo S.A')]</field> <field name="module_domain">[('author_ids', 'ilike', 'Odoo S.A')]</field>
<field name="module_type_id" ref="module_type_odoo"/> <field name="module_type_id" ref="module_type_odoo" />
</record> </record>
<record id="module_type_rule_odoo_b" model="ir.module.type.rule"> <record id="module_type_rule_odoo_b" model="ir.module.type.rule">
<field name="sequence">2</field> <field name="sequence">2</field>
<field name="module_domain">[('author_ids', 'ilike', 'OpenERP SA')]</field> <field name="module_domain">[('author_ids', 'ilike', 'OpenERP SA')]</field>
<field name="module_type_id" ref="module_type_odoo"/> <field name="module_type_id" ref="module_type_odoo" />
</record> </record>
<record id="module_type_rule_odoo_c" model="ir.module.type.rule"> <record id="module_type_rule_odoo_c" model="ir.module.type.rule">
<field name="sequence">3</field> <field name="sequence">3</field>
<field name="module_domain">[('author_ids', '=', 'Odoo SA')]</field> <field name="module_domain">[('author_ids', '=', 'Odoo SA')]</field>
<field name="module_type_id" ref="module_type_odoo"/> <field name="module_type_id" ref="module_type_odoo" />
</record> </record>
<record id="module_type_rule_odoo_d" model="ir.module.type.rule"> <record id="module_type_rule_odoo_d" model="ir.module.type.rule">
<field name="sequence">4</field> <field name="sequence">4</field>
<field name="module_domain">[('author_ids', '=', 'Odoo')]</field> <field name="module_domain">[('author_ids', '=', 'Odoo')]</field>
<field name="module_type_id" ref="module_type_odoo"/> <field name="module_type_id" ref="module_type_odoo" />
</record> </record>
<!-- OCA Rules --> <!-- OCA Rules -->
<record id="module_type_rule_oca_a" model="ir.module.type.rule"> <record id="module_type_rule_oca_a" model="ir.module.type.rule">
<field name="sequence">100</field> <field name="sequence">100</field>
<field name="module_domain">[('author_ids', '=', 'Odoo Community Association (OCA)')]</field> <field
<field name="module_type_id" ref="module_type_oca"/> name="module_domain"
>[('author_ids', '=', 'Odoo Community Association (OCA)')]</field>
<field name="module_type_id" ref="module_type_oca" />
</record> </record>
</odoo> </odoo>

View File

@ -6,13 +6,15 @@ from odoo import api, fields, models
class BaseModuleUpdate(models.TransientModel): class BaseModuleUpdate(models.TransientModel):
_inherit = 'base.module.update' _inherit = "base.module.update"
analyse_installed_modules = fields.Boolean( analyse_installed_modules = fields.Boolean(
string='Analyse Installed Modules', default=True) string="Analyse Installed Modules", default=True
)
@api.multi @api.multi
def update_module(self): def update_module(self):
return super(BaseModuleUpdate, self.with_context( return super(
analyse_installed_modules=self.analyse_installed_modules) BaseModuleUpdate,
self.with_context(analyse_installed_modules=self.analyse_installed_modules),
).update_module() ).update_module()

View File

@ -6,34 +6,41 @@ from odoo import api, fields, models
class IrModuleAuthor(models.Model): class IrModuleAuthor(models.Model):
_name = 'ir.module.author' _name = "ir.module.author"
_description = 'Modules Authors' _description = "Modules Authors"
name = fields.Char(string='Name', required=True) name = fields.Char(string="Name", required=True)
installed_module_ids = fields.Many2many( installed_module_ids = fields.Many2many(
string='Modules', comodel_name='ir.module.module', string="Modules",
relation='ir_module_module_author_rel') comodel_name="ir.module.module",
relation="ir_module_module_author_rel",
)
installed_module_qty = fields.Integer( installed_module_qty = fields.Integer(
string="Installed Modules Quantity", string="Installed Modules Quantity",
compute='_compute_installed_module_qty', store=True) compute="_compute_installed_module_qty",
store=True,
)
_sql_constraints = [ _sql_constraints = [
('name_uniq', 'unique(name)', (
'The name of the modules author should be unique per database!'), "name_uniq",
"unique(name)",
"The name of the modules author should be unique per database!",
),
] ]
@api.multi @api.multi
@api.depends('installed_module_ids') @api.depends("installed_module_ids")
def _compute_installed_module_qty(self): def _compute_installed_module_qty(self):
for author in self: for author in self:
author.installed_module_qty = len(author.installed_module_ids) author.installed_module_qty = len(author.installed_module_ids)
@api.model @api.model
def _get_or_create(self, name): def _get_or_create(self, name):
authors = self.search([('name', '=', name)]) authors = self.search([("name", "=", name)])
if authors: if authors:
return authors[0] return authors[0]
else: else:
return self.create({'name': name}) return self.create({"name": name})

View File

@ -2,39 +2,40 @@
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) # @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import os
import pygount
from pathlib import Path
import logging import logging
import os
from pathlib import Path
import pygount
from odoo import api, fields, models from odoo import api, fields, models
from odoo.tools.safe_eval import safe_eval
from odoo.modules.module import get_module_path from odoo.modules.module import get_module_path
from odoo.tools.safe_eval import safe_eval
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
class IrModuleModule(models.Model): class IrModuleModule(models.Model):
_inherit = 'ir.module.module' _inherit = "ir.module.module"
author_ids = fields.Many2many( author_ids = fields.Many2many(
string='Authors', comodel_name='ir.module.author', readonly=True, string="Authors",
relation='ir_module_module_author_rel') comodel_name="ir.module.author",
readonly=True,
relation="ir_module_module_author_rel",
)
module_type_id = fields.Many2one( module_type_id = fields.Many2one(
string='Module Type', comodel_name='ir.module.type', readonly=True) string="Module Type", comodel_name="ir.module.type", readonly=True
)
python_code_qty = fields.Integer( python_code_qty = fields.Integer(string="Python Code Quantity", readonly=True)
string='Python Code Quantity', readonly=True)
xml_code_qty = fields.Integer( xml_code_qty = fields.Integer(string="XML Code Quantity", readonly=True)
string='XML Code Quantity', readonly=True)
js_code_qty = fields.Integer( js_code_qty = fields.Integer(string="JS Code Quantity", readonly=True)
string='JS Code Quantity', readonly=True)
css_code_qty = fields.Integer( css_code_qty = fields.Integer(string="CSS Code Quantity", readonly=True)
string='CSS Code Quantity', readonly=True)
# Overloadable Section # Overloadable Section
@api.model @api.model
@ -51,76 +52,69 @@ class IrModuleModule(models.Model):
field_name: Odoo field name to store the analysis field_name: Odoo field name to store the analysis
""" """
return { return {
'.py': { ".py": {"code": "python_code_qty",},
'code': 'python_code_qty', ".xml": {"code": "xml_code_qty",},
}, ".js": {"code": "js_code_qty",},
'.xml': { ".css": {"code": "css_code_qty",},
'code': 'xml_code_qty',
},
'.js': {
'code': 'js_code_qty',
},
'.css': {
'code': 'css_code_qty',
},
} }
@api.model @api.model
def _get_clean_analyse_values(self): def _get_clean_analyse_values(self):
"""List of fields to unset when a module is uninstalled""" """List of fields to unset when a module is uninstalled"""
return { return {
'author_ids': [6, 0, []], "author_ids": [6, 0, []],
'module_type_id': False, "module_type_id": False,
'python_code_qty': False, "python_code_qty": False,
'xml_code_qty': 0, "xml_code_qty": 0,
'js_code_qty': 0, "js_code_qty": 0,
'css_code_qty': 0, "css_code_qty": 0,
} }
@api.model @api.model
def _get_module_encoding(self, file_ext): def _get_module_encoding(self, file_ext):
return 'utf-8' return "utf-8"
# Overload Section # Overload Section
@api.model @api.model
def update_list(self): def update_list(self):
res = super().update_list() res = super().update_list()
if self.env.context.get('analyse_installed_modules', False): if self.env.context.get("analyse_installed_modules", False):
self.search([('state', '=', 'installed')]).button_analyse_code() self.search([("state", "=", "installed")]).button_analyse_code()
return res return res
@api.multi @api.multi
def write(self, vals): def write(self, vals):
res = super().write(vals) res = super().write(vals)
if vals.get('state', False) == 'installed': if vals.get("state", False) == "installed":
self.button_analyse_code() self.button_analyse_code()
elif vals.get('state', False) == 'uninstalled'\ elif vals.get("state", False) == "uninstalled" and "module_analysis" not in [
and 'module_analysis' not in [x.name for x in self]: x.name for x in self
]:
self.write(self._get_clean_analyse_values()) self.write(self._get_clean_analyse_values())
return res return res
# Public Section # Public Section
@api.multi @api.multi
def button_analyse_code(self): def button_analyse_code(self):
IrModuleAuthor = self.env['ir.module.author'] IrModuleAuthor = self.env["ir.module.author"]
IrModuleTypeRule = self.env['ir.module.type.rule'] IrModuleTypeRule = self.env["ir.module.type.rule"]
rules = IrModuleTypeRule.search([]) rules = IrModuleTypeRule.search([])
cfg = self.env['ir.config_parameter'] cfg = self.env["ir.config_parameter"]
val = cfg.get_param('module_analysis.exclude_directories', '') val = cfg.get_param("module_analysis.exclude_directories", "")
exclude_directories = [x.strip() for x in val.split(',') if x.strip()] exclude_directories = [x.strip() for x in val.split(",") if x.strip()]
val = cfg.get_param('module_analysis.exclude_files', '') val = cfg.get_param("module_analysis.exclude_files", "")
exclude_files = [x.strip() for x in val.split(',') if x.strip()] exclude_files = [x.strip() for x in val.split(",") if x.strip()]
for module in self: for module in self:
_logger.info("Analysing Code for module %s ..." % (module.name)) _logger.info("Analysing Code for module %s ..." % (module.name))
# Update Authors, based on manifest key # Update Authors, based on manifest key
authors = [] authors = []
if module.author and module.author[0] == '[': if module.author and module.author[0] == "[":
author_txt_list = safe_eval(module.author) author_txt_list = safe_eval(module.author)
else: else:
author_txt_list = module.author.split(',') author_txt_list = module.author.split(",")
author_txt_list = [x.strip() for x in author_txt_list] author_txt_list = [x.strip() for x in author_txt_list]
author_txt_list = [x for x in author_txt_list if x] author_txt_list = [x for x in author_txt_list if x]
@ -141,27 +135,28 @@ class IrModuleModule(models.Model):
analysed_datas = self._get_analyse_data_dict() analysed_datas = self._get_analyse_data_dict()
file_extensions = analysed_datas.keys() file_extensions = analysed_datas.keys()
file_list = self._get_files_to_analyse( file_list = self._get_files_to_analyse(
module_path, file_extensions, exclude_directories, module_path, file_extensions, exclude_directories, exclude_files
exclude_files) )
for file_path, file_ext in file_list: for file_path, file_ext in file_list:
file_res = pygount.source_analysis( file_res = pygount.source_analysis(
file_path, '', file_path, "", encoding=self._get_module_encoding(file_ext)
encoding=self._get_module_encoding(file_ext)) )
for k, v in analysed_datas.get(file_ext).items(): for k, v in analysed_datas.get(file_ext).items():
v['value'] += getattr(file_res, k) v["value"] += getattr(file_res, k)
# Update the module with the datas # Update the module with the datas
values = {} values = {}
for file_ext, analyses in analysed_datas.items(): for file_ext, analyses in analysed_datas.items():
for k, v in analyses.items(): for k, v in analyses.items():
values[v['field']] = v['value'] values[v["field"]] = v["value"]
module.write(values) module.write(values)
# Custom Section # Custom Section
@api.model @api.model
def _get_files_to_analyse( def _get_files_to_analyse(
self, path, file_extensions, exclude_directories, exclude_files): self, path, file_extensions, exclude_directories, exclude_files
):
res = [] res = []
for root, dirs, files in os.walk(path, followlinks=True): for root, dirs, files in os.walk(path, followlinks=True):
if set(Path(root).parts) & set(exclude_directories): if set(Path(root).parts) & set(exclude_directories):
@ -179,8 +174,5 @@ class IrModuleModule(models.Model):
res_dict = self._get_analyse_settings().copy() res_dict = self._get_analyse_settings().copy()
for file_ext, analyse_dict in res_dict.items(): for file_ext, analyse_dict in res_dict.items():
for analyse_type, v in analyse_dict.items(): for analyse_type, v in analyse_dict.items():
analyse_dict[analyse_type] = { analyse_dict[analyse_type] = {"field": v, "value": 0}
'field': v,
'value': 0
}
return res_dict return res_dict

View File

@ -6,25 +6,26 @@ from odoo import api, fields, models
class IrModuleType(models.Model): class IrModuleType(models.Model):
_name = 'ir.module.type' _name = "ir.module.type"
_description = 'Modules Types' _description = "Modules Types"
_order = 'sequence' _order = "sequence"
name = fields.Char(string='Name', required=True) name = fields.Char(string="Name", required=True)
sequence = fields.Integer(string='Sequence') sequence = fields.Integer(string="Sequence")
installed_module_ids = fields.One2many( installed_module_ids = fields.One2many(
string='Installed Modules', comodel_name='ir.module.module', string="Installed Modules",
inverse_name='module_type_id') comodel_name="ir.module.module",
inverse_name="module_type_id",
)
installed_module_qty = fields.Integer( installed_module_qty = fields.Integer(
string='Modules Quantity', compute='_compute_installed_module_qty', string="Modules Quantity", compute="_compute_installed_module_qty", store=True
store=True) )
@api.multi @api.multi
@api.depends('installed_module_ids.module_type_id') @api.depends("installed_module_ids.module_type_id")
def _compute_installed_module_qty(self): def _compute_installed_module_qty(self):
for module_type in self: for module_type in self:
module_type.installed_module_qty = len( module_type.installed_module_qty = len(module_type.installed_module_ids)
module_type.installed_module_ids)

View File

@ -7,24 +7,24 @@ from odoo.tools.safe_eval import safe_eval
class IrModuleType(models.Model): class IrModuleType(models.Model):
_name = 'ir.module.type.rule' _name = "ir.module.type.rule"
_description = 'Modules Types Rules' _description = "Modules Types Rules"
_order = 'sequence' _order = "sequence"
sequence = fields.Integer(string='Sequence') sequence = fields.Integer(string="Sequence")
module_domain = fields.Char( module_domain = fields.Char(string="Module Domain", required=True, default="[]")
string='Module Domain', required=True, default='[]')
module_type_id = fields.Many2one( module_type_id = fields.Many2one(
string='Module type', comodel_name='ir.module.type', required=True) string="Module type", comodel_name="ir.module.type", required=True
)
@api.multi @api.multi
def _get_module_type_id_from_module(self, module): def _get_module_type_id_from_module(self, module):
IrModuleModule = self.env['ir.module.module'] IrModuleModule = self.env["ir.module.module"]
for rule in self: for rule in self:
domain = safe_eval(rule.module_domain) domain = safe_eval(rule.module_domain)
domain.append(('id', '=', module.id)) domain.append(("id", "=", module.id))
if IrModuleModule.search(domain): if IrModuleModule.search(domain):
return rule.module_type_id.id return rule.module_type_id.id
return False return False

View File

@ -2,12 +2,13 @@
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) # @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import api, SUPERUSER_ID from odoo import SUPERUSER_ID, api
def analyse_installed_modules(cr, registry): def analyse_installed_modules(cr, registry):
with api.Environment.manage(): with api.Environment.manage():
env = api.Environment(cr, SUPERUSER_ID, {}) env = api.Environment(cr, SUPERUSER_ID, {})
installed_modules = env['ir.module.module'].search( installed_modules = env["ir.module.module"].search(
[('state', '=', 'installed')]) [("state", "=", "installed")]
)
installed_modules.button_analyse_code() installed_modules.button_analyse_code()

View File

@ -5,4 +5,3 @@ Open the stats to analyse the detail of the code installed
.. image:: ../static/description/analysis_pivot.png .. image:: ../static/description/analysis_pivot.png
.. image:: ../static/description/analysis_pie.png .. image:: ../static/description/analysis_pie.png

View File

@ -7,27 +7,26 @@ from odoo.tests.common import TransactionCase, post_install
@post_install(True) @post_install(True)
class TestModule(TransactionCase): class TestModule(TransactionCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.IrModuleModule = self.env['ir.module.module'] self.IrModuleModule = self.env["ir.module.module"]
def test_installed_modules(self): def test_installed_modules(self):
installed_modules = self.IrModuleModule.search( installed_modules = self.IrModuleModule.search([("state", "=", "installed")])
[('state', '=', 'installed')])
for module in installed_modules: for module in installed_modules:
self.assertTrue( self.assertTrue(
module.python_code_qty > 0 or module.python_code_qty > 0
module.xml_code_qty > 0 or or module.xml_code_qty > 0
module.js_code_qty > 0, or module.js_code_qty > 0,
"module '%s' doesn't have code analysed defined, whereas it is" "module '%s' doesn't have code analysed defined, whereas it is"
" installed." % (module.name)) " installed." % (module.name),
)
def test_uninstalled_modules(self): def test_uninstalled_modules(self):
uninstalled_modules = self.IrModuleModule.search( uninstalled_modules = self.IrModuleModule.search([("state", "!=", "installed")])
[('state', '!=', 'installed')])
for module in uninstalled_modules: for module in uninstalled_modules:
self.assertTrue( self.assertTrue(
module.python_code_qty == 0, module.python_code_qty == 0,
"module '%s' has python lines defined, whereas it is" "module '%s' has python lines defined, whereas it is"
" not installed." % (module.name)) " not installed." % (module.name),
)

View File

@ -1,24 +1,27 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- <!--
Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>) Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain) @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
--> -->
<odoo> <odoo>
<menuitem
<menuitem id="menu_module_analysis" id="menu_module_analysis"
name="Analysis" name="Analysis"
parent="base.menu_management" sequence="100" parent="base.menu_management"
groups="base.group_no_one"/> sequence="100"
groups="base.group_no_one"
<menuitem id="menu_module_analysis_settings" />
<menuitem
id="menu_module_analysis_settings"
name="Settings" name="Settings"
parent="menu_module_analysis" sequence="10"/> parent="menu_module_analysis"
sequence="10"
<menuitem id="menu_module_analysis_reporting" />
<menuitem
id="menu_module_analysis_reporting"
name="Reporting" name="Reporting"
parent="menu_module_analysis" sequence="20"/> parent="menu_module_analysis"
sequence="20"
/>
</odoo> </odoo>

View File

@ -1,20 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- <!--
Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>) Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain) @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
--> -->
<odoo> <odoo>
<record id="view_base_module_update_form" model="ir.ui.view"> <record id="view_base_module_update_form" model="ir.ui.view">
<field name="model">base.module.update</field> <field name="model">base.module.update</field>
<field name="inherit_id" ref="base.view_base_module_update"/> <field name="inherit_id" ref="base.view_base_module_update" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr='//group[@states="init"]' position="inside"> <xpath expr='//group[@states="init"]' position="inside">
<field name="analyse_installed_modules"/> <field name="analyse_installed_modules" />
</xpath> </xpath>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@ -1,40 +1,39 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- <!--
Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>) Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain) @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
--> -->
<odoo> <odoo>
<record id="view_ir_module_author_form" model="ir.ui.view"> <record id="view_ir_module_author_form" model="ir.ui.view">
<field name="model">ir.module.author</field> <field name="model">ir.module.author</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form> <form>
<sheet> <sheet>
<div class="oe_title"> <div class="oe_title">
<div class="oe_edit_only"><label for="name"/></div> <div class="oe_edit_only">
<h1><field name="name"/></h1> <label for="name" />
</div>
<h1>
<field name="name" />
</h1>
</div> </div>
<group> <group>
<field name="installed_module_qty"/> <field name="installed_module_qty" />
</group> </group>
</sheet> </sheet>
</form> </form>
</field> </field>
</record> </record>
<record id="view_ir_module_author_tree" model="ir.ui.view"> <record id="view_ir_module_author_tree" model="ir.ui.view">
<field name="model">ir.module.author</field> <field name="model">ir.module.author</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree> <tree>
<field name="name"/> <field name="name" />
<field name="installed_module_qty"/> <field name="installed_module_qty" />
</tree> </tree>
</field> </field>
</record> </record>
<record id="action_ir_module_author" model="ir.actions.act_window"> <record id="action_ir_module_author" model="ir.actions.act_window">
<field name="name">Modules Authors</field> <field name="name">Modules Authors</field>
<field name="type">ir.actions.act_window</field> <field name="type">ir.actions.act_window</field>
@ -42,11 +41,11 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
<field name="view_type">form</field> <field name="view_type">form</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
</record> </record>
<menuitem
id="menu_module_authors"
<menuitem id="menu_module_authors" parent="menu_module_analysis_settings"
parent="menu_module_analysis_settings" sequence="1" sequence="1"
action="action_ir_module_author" action="action_ir_module_author"
groups="base.group_no_one"/> groups="base.group_no_one"
/>
</odoo> </odoo>

View File

@ -1,55 +1,55 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- <!--
Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>) Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain) @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
--> -->
<odoo> <odoo>
<record id="view_ir_module_module_form" model="ir.ui.view"> <record id="view_ir_module_module_form" model="ir.ui.view">
<field name="model">ir.module.module</field> <field name="model">ir.module.module</field>
<field name="inherit_id" ref="base.module_form"/> <field name="inherit_id" ref="base.module_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='state']/.." position="after"> <xpath expr="//field[@name='state']/.." position="after">
<button name="button_analyse_code" states="installed" string="Refresh Code Analysis" type="object" class="btn btn-primary"/> <button
name="button_analyse_code"
states="installed"
string="Refresh Code Analysis"
type="object"
class="btn btn-primary"
/>
<group string="Code Size" col="4"> <group string="Code Size" col="4">
<field name="python_code_qty"/> <field name="python_code_qty" />
<field name="xml_code_qty"/> <field name="xml_code_qty" />
<field name="js_code_qty"/> <field name="js_code_qty" />
<field name="css_code_qty"/> <field name="css_code_qty" />
</group> </group>
<group string="Type and Authors"> <group string="Type and Authors">
<field name="author_ids" widget="many2many_tags"/> <field name="author_ids" widget="many2many_tags" />
<field name="module_type_id"/> <field name="module_type_id" />
</group> </group>
</xpath> </xpath>
</field> </field>
</record> </record>
<record id="view_ir_module_module_pivot" model="ir.ui.view"> <record id="view_ir_module_module_pivot" model="ir.ui.view">
<field name="model">ir.module.module</field> <field name="model">ir.module.module</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<pivot> <pivot>
<field name="module_type_id" type="row"/> <field name="module_type_id" type="row" />
<field name="python_code_qty" type="measure"/> <field name="python_code_qty" type="measure" />
<field name="xml_code_qty" type="measure"/> <field name="xml_code_qty" type="measure" />
<field name="js_code_qty" type="measure"/> <field name="js_code_qty" type="measure" />
<field name="css_code_qty" type="measure"/> <field name="css_code_qty" type="measure" />
</pivot> </pivot>
</field> </field>
</record> </record>
<record id="view_ir_module_module_graph" model="ir.ui.view"> <record id="view_ir_module_module_graph" model="ir.ui.view">
<field name="model">ir.module.module</field> <field name="model">ir.module.module</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<graph type="pie"> <graph type="pie">
<field name="module_type_id" type="row"/> <field name="module_type_id" type="row" />
</graph> </graph>
</field> </field>
</record> </record>
<record id="action_ir_module_module_by_type" model="ir.actions.act_window"> <record id="action_ir_module_module_by_type" model="ir.actions.act_window">
<field name="name">Installed Modules by Types</field> <field name="name">Installed Modules by Types</field>
<field name="type">ir.actions.act_window</field> <field name="type">ir.actions.act_window</field>
@ -58,10 +58,11 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
<field name="view_type">form</field> <field name="view_type">form</field>
<field name="view_mode">pivot,graph</field> <field name="view_mode">pivot,graph</field>
</record> </record>
<menuitem
<menuitem id="menu_module_by_type" id="menu_module_by_type"
parent="menu_module_analysis_reporting" sequence="5" parent="menu_module_analysis_reporting"
sequence="5"
action="action_ir_module_module_by_type" action="action_ir_module_module_by_type"
groups="base.group_no_one"/> groups="base.group_no_one"
/>
</odoo> </odoo>

View File

@ -1,20 +1,22 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- <!--
Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>) Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain) @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
--> -->
<odoo> <odoo>
<record id="view_ir_module_type_form" model="ir.ui.view"> <record id="view_ir_module_type_form" model="ir.ui.view">
<field name="model">ir.module.type</field> <field name="model">ir.module.type</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form> <form>
<sheet> <sheet>
<div class="oe_title"> <div class="oe_title">
<div class="oe_edit_only"><label for="name"/></div> <div class="oe_edit_only">
<h1><field name="name"/></h1> <label for="name" />
</div>
<h1>
<field name="name" />
</h1>
</div> </div>
<group> <group>
</group> </group>
@ -22,17 +24,15 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
</form> </form>
</field> </field>
</record> </record>
<record id="view_ir_module_type_tree" model="ir.ui.view"> <record id="view_ir_module_type_tree" model="ir.ui.view">
<field name="model">ir.module.type</field> <field name="model">ir.module.type</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree> <tree>
<field name="name"/> <field name="name" />
<field name="installed_module_qty"/> <field name="installed_module_qty" />
</tree> </tree>
</field> </field>
</record> </record>
<record id="action_ir_module_type" model="ir.actions.act_window"> <record id="action_ir_module_type" model="ir.actions.act_window">
<field name="name">Modules Types</field> <field name="name">Modules Types</field>
<field name="type">ir.actions.act_window</field> <field name="type">ir.actions.act_window</field>
@ -40,11 +40,11 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
<field name="view_type">form</field> <field name="view_type">form</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
</record> </record>
<menuitem
id="menu_module_types"
<menuitem id="menu_module_types" parent="menu_module_analysis_settings"
parent="menu_module_analysis_settings" sequence="2" sequence="2"
action="action_ir_module_type" action="action_ir_module_type"
groups="base.group_no_one"/> groups="base.group_no_one"
/>
</odoo> </odoo>

View File

@ -1,23 +1,20 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- <!--
Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>) Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain) @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
--> -->
<odoo> <odoo>
<record id="view_ir_module_type_rule_tree" model="ir.ui.view"> <record id="view_ir_module_type_rule_tree" model="ir.ui.view">
<field name="model">ir.module.type.rule</field> <field name="model">ir.module.type.rule</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree editable="bottom"> <tree editable="bottom">
<field name="sequence" widget="handle"/> <field name="sequence" widget="handle" />
<field name="module_type_id"/> <field name="module_type_id" />
<field name="module_domain"/> <field name="module_domain" />
</tree> </tree>
</field> </field>
</record> </record>
<record id="action_ir_module_type_rule" model="ir.actions.act_window"> <record id="action_ir_module_type_rule" model="ir.actions.act_window">
<field name="name">Modules Types Rules</field> <field name="name">Modules Types Rules</field>
<field name="type">ir.actions.act_window</field> <field name="type">ir.actions.act_window</field>
@ -25,10 +22,11 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
<field name="view_type">form</field> <field name="view_type">form</field>
<field name="view_mode">tree</field> <field name="view_mode">tree</field>
</record> </record>
<menuitem
<menuitem id="menu_module_type_rules" id="menu_module_type_rules"
parent="menu_module_analysis_settings" sequence="3" parent="menu_module_analysis_settings"
sequence="3"
action="action_ir_module_type_rule" action="action_ir_module_type_rule"
groups="base.group_no_one"/> groups="base.group_no_one"
/>
</odoo> </odoo>