[IMP] module_analysis: black, isort, prettier
parent
2e88c5b31e
commit
8fc7d87806
|
@ -1,2 +1,2 @@
|
|||
from . import models
|
||||
from . post_init_hook import analyse_installed_modules
|
||||
from .post_init_hook import analyse_installed_modules
|
||||
|
|
|
@ -3,32 +3,28 @@
|
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
{
|
||||
'name': "Module Analysis",
|
||||
'summary': "Add analysis tools regarding installed modules"
|
||||
"name": "Module Analysis",
|
||||
"summary": "Add analysis tools regarding installed modules"
|
||||
" to know which installed modules comes from Odoo Core, OCA, or are"
|
||||
" custom modules",
|
||||
'author': 'GRAP, Odoo Community Association (OCA)',
|
||||
'website': "https://github.com/OCA/server-tools/",
|
||||
'version': '12.0.1.0.0',
|
||||
'license': 'AGPL-3',
|
||||
'depends': [
|
||||
'base',
|
||||
"author": "GRAP, Odoo Community Association (OCA)",
|
||||
"website": "https://github.com/OCA/server-tools/",
|
||||
"version": "12.0.1.0.0",
|
||||
"license": "AGPL-3",
|
||||
"depends": ["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': [
|
||||
'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',
|
||||
],
|
||||
'external_dependencies': {
|
||||
'python': ['pygount'],
|
||||
},
|
||||
'post_init_hook': 'analyse_installed_modules',
|
||||
'installable': True,
|
||||
"external_dependencies": {"python": ["pygount"],},
|
||||
"post_init_hook": "analyse_installed_modules",
|
||||
"installable": True,
|
||||
}
|
||||
|
|
|
@ -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/>)
|
||||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
-->
|
||||
|
||||
<odoo noupdate="1">
|
||||
|
||||
<record id="parameter_exclude_directories" model="ir.config_parameter">
|
||||
<field name="key">module_analysis.exclude_directories</field>
|
||||
<field name="value">lib,demo,test,tests,doc,description</field>
|
||||
</record>
|
||||
|
||||
<record id="parameter_exclude_files" model="ir.config_parameter">
|
||||
<field name="key">module_analysis.exclude_files</field>
|
||||
<field name="value">__openerp__.py,__manifest__.py</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
|
|
@ -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/>)
|
||||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
<record id="module_type_odoo" model="ir.module.type">
|
||||
<field name="name">Odoo Core</field>
|
||||
</record>
|
||||
|
||||
<record id="module_type_oca" model="ir.module.type">
|
||||
<field name="name">OCA</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
|
|
@ -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/>)
|
||||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
<!-- Odoo Rules -->
|
||||
<record id="module_type_rule_odoo_a" model="ir.module.type.rule">
|
||||
<field name="sequence">1</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 id="module_type_rule_odoo_b" model="ir.module.type.rule">
|
||||
<field name="sequence">2</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 id="module_type_rule_odoo_c" model="ir.module.type.rule">
|
||||
<field name="sequence">3</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 id="module_type_rule_odoo_d" model="ir.module.type.rule">
|
||||
<field name="sequence">4</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>
|
||||
|
||||
<!-- OCA Rules -->
|
||||
<record id="module_type_rule_oca_a" model="ir.module.type.rule">
|
||||
<field name="sequence">100</field>
|
||||
<field name="module_domain">[('author_ids', '=', 'Odoo Community Association (OCA)')]</field>
|
||||
<field name="module_type_id" ref="module_type_oca"/>
|
||||
<field
|
||||
name="module_domain"
|
||||
>[('author_ids', '=', 'Odoo Community Association (OCA)')]</field>
|
||||
<field name="module_type_id" ref="module_type_oca" />
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
|
|
@ -6,13 +6,15 @@ from odoo import api, fields, models
|
|||
|
||||
|
||||
class BaseModuleUpdate(models.TransientModel):
|
||||
_inherit = 'base.module.update'
|
||||
_inherit = "base.module.update"
|
||||
|
||||
analyse_installed_modules = fields.Boolean(
|
||||
string='Analyse Installed Modules', default=True)
|
||||
string="Analyse Installed Modules", default=True
|
||||
)
|
||||
|
||||
@api.multi
|
||||
def update_module(self):
|
||||
return super(BaseModuleUpdate, self.with_context(
|
||||
analyse_installed_modules=self.analyse_installed_modules)
|
||||
return super(
|
||||
BaseModuleUpdate,
|
||||
self.with_context(analyse_installed_modules=self.analyse_installed_modules),
|
||||
).update_module()
|
||||
|
|
|
@ -6,34 +6,41 @@ from odoo import api, fields, models
|
|||
|
||||
|
||||
class IrModuleAuthor(models.Model):
|
||||
_name = 'ir.module.author'
|
||||
_description = 'Modules Authors'
|
||||
_name = "ir.module.author"
|
||||
_description = "Modules Authors"
|
||||
|
||||
name = fields.Char(string='Name', required=True)
|
||||
name = fields.Char(string="Name", required=True)
|
||||
|
||||
installed_module_ids = fields.Many2many(
|
||||
string='Modules', comodel_name='ir.module.module',
|
||||
relation='ir_module_module_author_rel')
|
||||
string="Modules",
|
||||
comodel_name="ir.module.module",
|
||||
relation="ir_module_module_author_rel",
|
||||
)
|
||||
|
||||
installed_module_qty = fields.Integer(
|
||||
string="Installed Modules Quantity",
|
||||
compute='_compute_installed_module_qty', store=True)
|
||||
compute="_compute_installed_module_qty",
|
||||
store=True,
|
||||
)
|
||||
|
||||
_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.depends('installed_module_ids')
|
||||
@api.depends("installed_module_ids")
|
||||
def _compute_installed_module_qty(self):
|
||||
for author in self:
|
||||
author.installed_module_qty = len(author.installed_module_ids)
|
||||
|
||||
@api.model
|
||||
def _get_or_create(self, name):
|
||||
authors = self.search([('name', '=', name)])
|
||||
authors = self.search([("name", "=", name)])
|
||||
if authors:
|
||||
return authors[0]
|
||||
else:
|
||||
return self.create({'name': name})
|
||||
return self.create({"name": name})
|
||||
|
|
|
@ -2,39 +2,40 @@
|
|||
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import os
|
||||
import pygount
|
||||
from pathlib import Path
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import pygount
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
from odoo.modules.module import get_module_path
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IrModuleModule(models.Model):
|
||||
_inherit = 'ir.module.module'
|
||||
_inherit = "ir.module.module"
|
||||
|
||||
author_ids = fields.Many2many(
|
||||
string='Authors', comodel_name='ir.module.author', readonly=True,
|
||||
relation='ir_module_module_author_rel')
|
||||
string="Authors",
|
||||
comodel_name="ir.module.author",
|
||||
readonly=True,
|
||||
relation="ir_module_module_author_rel",
|
||||
)
|
||||
|
||||
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(
|
||||
string='Python Code Quantity', readonly=True)
|
||||
python_code_qty = fields.Integer(string="Python Code Quantity", readonly=True)
|
||||
|
||||
xml_code_qty = fields.Integer(
|
||||
string='XML Code Quantity', readonly=True)
|
||||
xml_code_qty = fields.Integer(string="XML Code Quantity", readonly=True)
|
||||
|
||||
js_code_qty = fields.Integer(
|
||||
string='JS Code Quantity', readonly=True)
|
||||
js_code_qty = fields.Integer(string="JS Code Quantity", readonly=True)
|
||||
|
||||
css_code_qty = fields.Integer(
|
||||
string='CSS Code Quantity', readonly=True)
|
||||
css_code_qty = fields.Integer(string="CSS Code Quantity", readonly=True)
|
||||
|
||||
# Overloadable Section
|
||||
@api.model
|
||||
|
@ -51,76 +52,69 @@ class IrModuleModule(models.Model):
|
|||
field_name: Odoo field name to store the analysis
|
||||
"""
|
||||
return {
|
||||
'.py': {
|
||||
'code': 'python_code_qty',
|
||||
},
|
||||
'.xml': {
|
||||
'code': 'xml_code_qty',
|
||||
},
|
||||
'.js': {
|
||||
'code': 'js_code_qty',
|
||||
},
|
||||
'.css': {
|
||||
'code': 'css_code_qty',
|
||||
},
|
||||
".py": {"code": "python_code_qty",},
|
||||
".xml": {"code": "xml_code_qty",},
|
||||
".js": {"code": "js_code_qty",},
|
||||
".css": {"code": "css_code_qty",},
|
||||
}
|
||||
|
||||
@api.model
|
||||
def _get_clean_analyse_values(self):
|
||||
"""List of fields to unset when a module is uninstalled"""
|
||||
return {
|
||||
'author_ids': [6, 0, []],
|
||||
'module_type_id': False,
|
||||
'python_code_qty': False,
|
||||
'xml_code_qty': 0,
|
||||
'js_code_qty': 0,
|
||||
'css_code_qty': 0,
|
||||
"author_ids": [6, 0, []],
|
||||
"module_type_id": False,
|
||||
"python_code_qty": False,
|
||||
"xml_code_qty": 0,
|
||||
"js_code_qty": 0,
|
||||
"css_code_qty": 0,
|
||||
}
|
||||
|
||||
@api.model
|
||||
def _get_module_encoding(self, file_ext):
|
||||
return 'utf-8'
|
||||
return "utf-8"
|
||||
|
||||
# Overload Section
|
||||
@api.model
|
||||
def update_list(self):
|
||||
res = super().update_list()
|
||||
if self.env.context.get('analyse_installed_modules', False):
|
||||
self.search([('state', '=', 'installed')]).button_analyse_code()
|
||||
if self.env.context.get("analyse_installed_modules", False):
|
||||
self.search([("state", "=", "installed")]).button_analyse_code()
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
res = super().write(vals)
|
||||
if vals.get('state', False) == 'installed':
|
||||
if vals.get("state", False) == "installed":
|
||||
self.button_analyse_code()
|
||||
elif vals.get('state', False) == 'uninstalled'\
|
||||
and 'module_analysis' not in [x.name for x in self]:
|
||||
elif vals.get("state", False) == "uninstalled" and "module_analysis" not in [
|
||||
x.name for x in self
|
||||
]:
|
||||
self.write(self._get_clean_analyse_values())
|
||||
return res
|
||||
|
||||
# Public Section
|
||||
@api.multi
|
||||
def button_analyse_code(self):
|
||||
IrModuleAuthor = self.env['ir.module.author']
|
||||
IrModuleTypeRule = self.env['ir.module.type.rule']
|
||||
IrModuleAuthor = self.env["ir.module.author"]
|
||||
IrModuleTypeRule = self.env["ir.module.type.rule"]
|
||||
rules = IrModuleTypeRule.search([])
|
||||
|
||||
cfg = self.env['ir.config_parameter']
|
||||
val = cfg.get_param('module_analysis.exclude_directories', '')
|
||||
exclude_directories = [x.strip() for x in val.split(',') if x.strip()]
|
||||
val = cfg.get_param('module_analysis.exclude_files', '')
|
||||
exclude_files = [x.strip() for x in val.split(',') if x.strip()]
|
||||
cfg = self.env["ir.config_parameter"]
|
||||
val = cfg.get_param("module_analysis.exclude_directories", "")
|
||||
exclude_directories = [x.strip() for x in val.split(",") if x.strip()]
|
||||
val = cfg.get_param("module_analysis.exclude_files", "")
|
||||
exclude_files = [x.strip() for x in val.split(",") if x.strip()]
|
||||
|
||||
for module in self:
|
||||
_logger.info("Analysing Code for module %s ..." % (module.name))
|
||||
|
||||
# Update Authors, based on manifest key
|
||||
authors = []
|
||||
if module.author and module.author[0] == '[':
|
||||
if module.author and module.author[0] == "[":
|
||||
author_txt_list = safe_eval(module.author)
|
||||
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 for x in author_txt_list if x]
|
||||
|
@ -141,27 +135,28 @@ class IrModuleModule(models.Model):
|
|||
analysed_datas = self._get_analyse_data_dict()
|
||||
file_extensions = analysed_datas.keys()
|
||||
file_list = self._get_files_to_analyse(
|
||||
module_path, file_extensions, exclude_directories,
|
||||
exclude_files)
|
||||
module_path, file_extensions, exclude_directories, exclude_files
|
||||
)
|
||||
|
||||
for file_path, file_ext in file_list:
|
||||
file_res = pygount.source_analysis(
|
||||
file_path, '',
|
||||
encoding=self._get_module_encoding(file_ext))
|
||||
file_path, "", encoding=self._get_module_encoding(file_ext)
|
||||
)
|
||||
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
|
||||
values = {}
|
||||
for file_ext, analyses in analysed_datas.items():
|
||||
for k, v in analyses.items():
|
||||
values[v['field']] = v['value']
|
||||
values[v["field"]] = v["value"]
|
||||
module.write(values)
|
||||
|
||||
# Custom Section
|
||||
@api.model
|
||||
def _get_files_to_analyse(
|
||||
self, path, file_extensions, exclude_directories, exclude_files):
|
||||
self, path, file_extensions, exclude_directories, exclude_files
|
||||
):
|
||||
res = []
|
||||
for root, dirs, files in os.walk(path, followlinks=True):
|
||||
if set(Path(root).parts) & set(exclude_directories):
|
||||
|
@ -179,8 +174,5 @@ class IrModuleModule(models.Model):
|
|||
res_dict = self._get_analyse_settings().copy()
|
||||
for file_ext, analyse_dict in res_dict.items():
|
||||
for analyse_type, v in analyse_dict.items():
|
||||
analyse_dict[analyse_type] = {
|
||||
'field': v,
|
||||
'value': 0
|
||||
}
|
||||
analyse_dict[analyse_type] = {"field": v, "value": 0}
|
||||
return res_dict
|
||||
|
|
|
@ -6,25 +6,26 @@ from odoo import api, fields, models
|
|||
|
||||
|
||||
class IrModuleType(models.Model):
|
||||
_name = 'ir.module.type'
|
||||
_description = 'Modules Types'
|
||||
_order = 'sequence'
|
||||
_name = "ir.module.type"
|
||||
_description = "Modules Types"
|
||||
_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(
|
||||
string='Installed Modules', comodel_name='ir.module.module',
|
||||
inverse_name='module_type_id')
|
||||
string="Installed Modules",
|
||||
comodel_name="ir.module.module",
|
||||
inverse_name="module_type_id",
|
||||
)
|
||||
|
||||
installed_module_qty = fields.Integer(
|
||||
string='Modules Quantity', compute='_compute_installed_module_qty',
|
||||
store=True)
|
||||
string="Modules Quantity", compute="_compute_installed_module_qty", store=True
|
||||
)
|
||||
|
||||
@api.multi
|
||||
@api.depends('installed_module_ids.module_type_id')
|
||||
@api.depends("installed_module_ids.module_type_id")
|
||||
def _compute_installed_module_qty(self):
|
||||
for module_type in self:
|
||||
module_type.installed_module_qty = len(
|
||||
module_type.installed_module_ids)
|
||||
module_type.installed_module_qty = len(module_type.installed_module_ids)
|
||||
|
|
|
@ -7,24 +7,24 @@ from odoo.tools.safe_eval import safe_eval
|
|||
|
||||
|
||||
class IrModuleType(models.Model):
|
||||
_name = 'ir.module.type.rule'
|
||||
_description = 'Modules Types Rules'
|
||||
_order = 'sequence'
|
||||
_name = "ir.module.type.rule"
|
||||
_description = "Modules Types Rules"
|
||||
_order = "sequence"
|
||||
|
||||
sequence = fields.Integer(string='Sequence')
|
||||
sequence = fields.Integer(string="Sequence")
|
||||
|
||||
module_domain = fields.Char(
|
||||
string='Module Domain', required=True, default='[]')
|
||||
module_domain = fields.Char(string="Module Domain", required=True, default="[]")
|
||||
|
||||
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
|
||||
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:
|
||||
domain = safe_eval(rule.module_domain)
|
||||
domain.append(('id', '=', module.id))
|
||||
domain.append(("id", "=", module.id))
|
||||
if IrModuleModule.search(domain):
|
||||
return rule.module_type_id.id
|
||||
return False
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
||||
# 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):
|
||||
with api.Environment.manage():
|
||||
env = api.Environment(cr, SUPERUSER_ID, {})
|
||||
installed_modules = env['ir.module.module'].search(
|
||||
[('state', '=', 'installed')])
|
||||
installed_modules = env["ir.module.module"].search(
|
||||
[("state", "=", "installed")]
|
||||
)
|
||||
installed_modules.button_analyse_code()
|
||||
|
|
|
@ -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_pie.png
|
||||
|
||||
|
|
|
@ -7,27 +7,26 @@ from odoo.tests.common import TransactionCase, post_install
|
|||
|
||||
@post_install(True)
|
||||
class TestModule(TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.IrModuleModule = self.env['ir.module.module']
|
||||
self.IrModuleModule = self.env["ir.module.module"]
|
||||
|
||||
def test_installed_modules(self):
|
||||
installed_modules = self.IrModuleModule.search(
|
||||
[('state', '=', 'installed')])
|
||||
installed_modules = self.IrModuleModule.search([("state", "=", "installed")])
|
||||
for module in installed_modules:
|
||||
self.assertTrue(
|
||||
module.python_code_qty > 0 or
|
||||
module.xml_code_qty > 0 or
|
||||
module.js_code_qty > 0,
|
||||
module.python_code_qty > 0
|
||||
or module.xml_code_qty > 0
|
||||
or module.js_code_qty > 0,
|
||||
"module '%s' doesn't have code analysed defined, whereas it is"
|
||||
" installed." % (module.name))
|
||||
" installed." % (module.name),
|
||||
)
|
||||
|
||||
def test_uninstalled_modules(self):
|
||||
uninstalled_modules = self.IrModuleModule.search(
|
||||
[('state', '!=', 'installed')])
|
||||
uninstalled_modules = self.IrModuleModule.search([("state", "!=", "installed")])
|
||||
for module in uninstalled_modules:
|
||||
self.assertTrue(
|
||||
module.python_code_qty == 0,
|
||||
"module '%s' has python lines defined, whereas it is"
|
||||
" not installed." % (module.name))
|
||||
" not installed." % (module.name),
|
||||
)
|
||||
|
|
|
@ -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/>)
|
||||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
<menuitem id="menu_module_analysis"
|
||||
<menuitem
|
||||
id="menu_module_analysis"
|
||||
name="Analysis"
|
||||
parent="base.menu_management" sequence="100"
|
||||
groups="base.group_no_one"/>
|
||||
|
||||
<menuitem id="menu_module_analysis_settings"
|
||||
parent="base.menu_management"
|
||||
sequence="100"
|
||||
groups="base.group_no_one"
|
||||
/>
|
||||
<menuitem
|
||||
id="menu_module_analysis_settings"
|
||||
name="Settings"
|
||||
parent="menu_module_analysis" sequence="10"/>
|
||||
|
||||
<menuitem id="menu_module_analysis_reporting"
|
||||
parent="menu_module_analysis"
|
||||
sequence="10"
|
||||
/>
|
||||
<menuitem
|
||||
id="menu_module_analysis_reporting"
|
||||
name="Reporting"
|
||||
parent="menu_module_analysis" sequence="20"/>
|
||||
|
||||
|
||||
parent="menu_module_analysis"
|
||||
sequence="20"
|
||||
/>
|
||||
</odoo>
|
||||
|
|
|
@ -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/>)
|
||||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
<record id="view_base_module_update_form" model="ir.ui.view">
|
||||
<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">
|
||||
<xpath expr='//group[@states="init"]' position="inside">
|
||||
<field name="analyse_installed_modules"/>
|
||||
<field name="analyse_installed_modules" />
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
|
|
@ -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/>)
|
||||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
<record id="view_ir_module_author_form" model="ir.ui.view">
|
||||
<field name="model">ir.module.author</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<div class="oe_edit_only"><label for="name"/></div>
|
||||
<h1><field name="name"/></h1>
|
||||
<div class="oe_edit_only">
|
||||
<label for="name" />
|
||||
</div>
|
||||
<h1>
|
||||
<field name="name" />
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<field name="installed_module_qty"/>
|
||||
<field name="installed_module_qty" />
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="view_ir_module_author_tree" model="ir.ui.view">
|
||||
<field name="model">ir.module.author</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="name"/>
|
||||
<field name="installed_module_qty"/>
|
||||
<field name="name" />
|
||||
<field name="installed_module_qty" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_ir_module_author" model="ir.actions.act_window">
|
||||
<field name="name">Modules Authors</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_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
|
||||
<menuitem id="menu_module_authors"
|
||||
parent="menu_module_analysis_settings" sequence="1"
|
||||
<menuitem
|
||||
id="menu_module_authors"
|
||||
parent="menu_module_analysis_settings"
|
||||
sequence="1"
|
||||
action="action_ir_module_author"
|
||||
groups="base.group_no_one"/>
|
||||
|
||||
groups="base.group_no_one"
|
||||
/>
|
||||
</odoo>
|
||||
|
|
|
@ -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/>)
|
||||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
<record id="view_ir_module_module_form" model="ir.ui.view">
|
||||
<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">
|
||||
<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">
|
||||
<field name="python_code_qty"/>
|
||||
<field name="xml_code_qty"/>
|
||||
<field name="js_code_qty"/>
|
||||
<field name="css_code_qty"/>
|
||||
<field name="python_code_qty" />
|
||||
<field name="xml_code_qty" />
|
||||
<field name="js_code_qty" />
|
||||
<field name="css_code_qty" />
|
||||
</group>
|
||||
<group string="Type and Authors">
|
||||
<field name="author_ids" widget="many2many_tags"/>
|
||||
<field name="module_type_id"/>
|
||||
<field name="author_ids" widget="many2many_tags" />
|
||||
<field name="module_type_id" />
|
||||
</group>
|
||||
</xpath>
|
||||
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_ir_module_module_pivot" model="ir.ui.view">
|
||||
<field name="model">ir.module.module</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot>
|
||||
<field name="module_type_id" type="row"/>
|
||||
<field name="python_code_qty" type="measure"/>
|
||||
<field name="xml_code_qty" type="measure"/>
|
||||
<field name="js_code_qty" type="measure"/>
|
||||
<field name="css_code_qty" type="measure"/>
|
||||
<field name="module_type_id" type="row" />
|
||||
<field name="python_code_qty" type="measure" />
|
||||
<field name="xml_code_qty" type="measure" />
|
||||
<field name="js_code_qty" type="measure" />
|
||||
<field name="css_code_qty" type="measure" />
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_ir_module_module_graph" model="ir.ui.view">
|
||||
<field name="model">ir.module.module</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph type="pie">
|
||||
<field name="module_type_id" type="row"/>
|
||||
<field name="module_type_id" type="row" />
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_ir_module_module_by_type" model="ir.actions.act_window">
|
||||
<field name="name">Installed Modules by Types</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_mode">pivot,graph</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_module_by_type"
|
||||
parent="menu_module_analysis_reporting" sequence="5"
|
||||
<menuitem
|
||||
id="menu_module_by_type"
|
||||
parent="menu_module_analysis_reporting"
|
||||
sequence="5"
|
||||
action="action_ir_module_module_by_type"
|
||||
groups="base.group_no_one"/>
|
||||
|
||||
groups="base.group_no_one"
|
||||
/>
|
||||
</odoo>
|
||||
|
|
|
@ -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/>)
|
||||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
<record id="view_ir_module_type_form" model="ir.ui.view">
|
||||
<field name="model">ir.module.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<div class="oe_edit_only"><label for="name"/></div>
|
||||
<h1><field name="name"/></h1>
|
||||
<div class="oe_edit_only">
|
||||
<label for="name" />
|
||||
</div>
|
||||
<h1>
|
||||
<field name="name" />
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
</group>
|
||||
|
@ -22,17 +24,15 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
|||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_ir_module_type_tree" model="ir.ui.view">
|
||||
<field name="model">ir.module.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="name"/>
|
||||
<field name="installed_module_qty"/>
|
||||
<field name="name" />
|
||||
<field name="installed_module_qty" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_ir_module_type" model="ir.actions.act_window">
|
||||
<field name="name">Modules Types</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_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
|
||||
<menuitem id="menu_module_types"
|
||||
parent="menu_module_analysis_settings" sequence="2"
|
||||
<menuitem
|
||||
id="menu_module_types"
|
||||
parent="menu_module_analysis_settings"
|
||||
sequence="2"
|
||||
action="action_ir_module_type"
|
||||
groups="base.group_no_one"/>
|
||||
|
||||
groups="base.group_no_one"
|
||||
/>
|
||||
</odoo>
|
||||
|
|
|
@ -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/>)
|
||||
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
<record id="view_ir_module_type_rule_tree" model="ir.ui.view">
|
||||
<field name="model">ir.module.type.rule</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="module_type_id"/>
|
||||
<field name="module_domain"/>
|
||||
<field name="sequence" widget="handle" />
|
||||
<field name="module_type_id" />
|
||||
<field name="module_domain" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_ir_module_type_rule" model="ir.actions.act_window">
|
||||
<field name="name">Modules Types Rules</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_mode">tree</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_module_type_rules"
|
||||
parent="menu_module_analysis_settings" sequence="3"
|
||||
<menuitem
|
||||
id="menu_module_type_rules"
|
||||
parent="menu_module_analysis_settings"
|
||||
sequence="3"
|
||||
action="action_ir_module_type_rule"
|
||||
groups="base.group_no_one"/>
|
||||
|
||||
groups="base.group_no_one"
|
||||
/>
|
||||
</odoo>
|
||||
|
|
Loading…
Reference in New Issue