Merge PR #2609 into 16.0

Signed-off-by bguillot
pull/2624/head
OCA-git-bot 2023-05-16 11:15:43 +00:00
commit f90e1b63c3
42 changed files with 2162 additions and 0 deletions

View File

@ -0,0 +1,187 @@
===============
Module Analysis
===============
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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%2Fserver--tools-lightgray.png?logo=github
:target: https://github.com/OCA/server-tools/tree/15.0/module_analysis
:alt: OCA/server-tools
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/server-tools-15-0/server-tools-15-0-module_analysis
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/149/15.0
:alt: Try me on Runbot
|badge1| |badge2| |badge3| |badge4| |badge5|
This module allows you to know 'how much code' is running on your Odoo
instance, group by 'Type' (Odoo Core, OCA, other...)
This module can be usefull in the following cases :
* To analyse the size of your technical debt, regarding your Custom modules
* To know the ratio between Odoo / OCA and Custom modules
* To evaluate the amount to pay to odoo to upgrade your custom code, or the
induced workload
.. image:: https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/installed_modules_by_types.png
For that purpose, it adds new concepts
* ``ir.module.author``, based on the value ``author`` present in the manifest
file.
.. image:: https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/module_authors.png
* ``ir.module.type``, populated by default with Odoo and OCA values.
.. image:: https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/module_types.png
Each installed modules have extra data in the 'Technical Data' tab :
.. image:: https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/module_form.png
**Table of contents**
.. contents::
:local:
Installation
============
To use this module, you have to install the ``pygount`` python librairy.
``pip install pygount``
Configuration
=============
* Go to Apps / Module Analysis / Modules Types Rules
The Module types Rules are usefull to get the Type of a module, based on
it information.
This module comes with default rules.
.. image:: https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/default_module_type_rules.png
You can add your custom rules to identify the modules your team have
developped for exemple,
.. image:: https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/add_module_type_rules.png
to update the data manually, you have to :
* Go to 'Apps' / 'Update Apps List'
* Check the box 'Analyse Installed modules'
.. image:: https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/base_module_update.png
This will update analysis of your installed modules.
to update the data automatically, you have to :
* Go to 'Settings' / 'Technical' / 'Scheduled Actions'
* Configure the action 'Update Module Analysis'. (By default, the analysis will be done nightly)
Adding Extra data
~~~~~~~~~~~~~~~~~
If you want to analyse other data, (for exemple, having the number of HTML
files), create a custom modules and overload the module model :
.. code-block:: python
from odoo import api, fields, models
class IrModuleModule(models.Model):
_inherit = 'ir.module.module'
xml_documentation_qty = fields.Integer(
string='Quantity of Comments in XML Files')
@api.model
def _get_analyse_settings(self):
res = super()._get_analyse_settings()
if not '.html' in res:
res['.html'] = {}
res['.html']['documentation'] 'xml_documentation_qty'
return res
Exclude files and directories
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Two parameters are availaible in 'Settings' / 'Technical' / 'Parameters'
'System Parameters' :
.. image:: https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/config_parameters.png
The list of folders and filename will be exclude from the analysis.
You can change the default settings.
Usage
=====
* Go to 'Apps' / 'Module Analysis' / 'Installed module by Types'
Open the stats to analyse the detail of the code installed
.. image:: https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/analysis_pivot.png
.. image:: https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/analysis_pie.png
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/server-tools/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/server-tools/issues/new?body=module:%20module_analysis%0Aversion:%2015.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
~~~~~~~
* GRAP
Contributors
~~~~~~~~~~~~
* Sylvain LE GAL (https://twitter.com/legalsylvain)
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/server-tools <https://github.com/OCA/server-tools/tree/15.0/module_analysis>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@ -0,0 +1 @@
from . import models

View File

@ -0,0 +1,33 @@
# 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).
{
"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)",
"maintainers": ["legalsylvain"],
"website": "https://github.com/OCA/server-tools",
"version": "16.0.1.0.0",
"license": "AGPL-3",
"depends": ["base"],
"data": [
"security/ir.model.access.csv",
"views/menu.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_cron.xml",
"data/ir_config_parameter.xml",
"data/ir_module_type.xml",
"data/ir_module_type_rule.xml",
"data/ir_cron.xml",
],
"external_dependencies": {
"python": ["pygount"],
},
"installable": True,
}

View File

@ -0,0 +1,16 @@
<?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>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright (C) 2021-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="cron_module_analysis" model="ir.cron">
<field name="name">Update Module Analysis</field>
<field name="active" eval="False" />
<field name="model_id" ref="base.model_ir_module_module" />
<field name="state">code</field>
<field name="code">model.cron_analyse_code()</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="nextcall" eval="(DateTime.today()).strftime('%Y-%m-%d')" />
<field name="numbercall">-1</field>
<field name="user_id" ref="base.user_root" />
</record>
</odoo>

View File

@ -0,0 +1,14 @@
<?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>

View File

@ -0,0 +1,37 @@
<?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" />
</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" />
</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" />
</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" />
</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" />
</record>
</odoo>

View File

@ -0,0 +1,222 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * module_analysis
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-03-07 19:33+0000\n"
"Last-Translator: Francesco Foresti <francesco.foresti@ooops404.com>\n"
"Language-Team: none\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.14.1\n"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_base_module_update__analyse_installed_modules
msgid "Analyse Installed Modules"
msgstr "Analizza Moduli Installati"
#. module: module_analysis
#: model:ir.ui.menu,name:module_analysis.menu_module_analysis
msgid "Analysis"
msgstr "Analisi"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_module__author_ids
msgid "Authors"
msgstr "Autori"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_module__css_code_qty
msgid "CSS Code Quantity"
msgstr "Quantità Codice CSS"
#. module: module_analysis
#: model_terms:ir.ui.view,arch_db:module_analysis.view_ir_module_module_form
msgid "Code Size"
msgstr "Dimensione Codice"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__create_uid
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__create_uid
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__create_uid
msgid "Created by"
msgstr "Creato da"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__create_date
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__create_date
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__create_date
msgid "Created on"
msgstr "Creato il"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__display_name
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__display_name
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__display_name
msgid "Display Name"
msgstr "Nome Visualizzato"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__id
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__id
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__id
msgid "ID"
msgstr "ID"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__installed_module_ids
msgid "Installed Modules"
msgstr "Moduli Installati"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__installed_module_qty
msgid "Installed Modules Quantity"
msgstr "Quantità Moduli Installati"
#. module: module_analysis
#: model:ir.actions.act_window,name:module_analysis.action_ir_module_module_by_type
#: model:ir.ui.menu,name:module_analysis.menu_module_by_type
msgid "Installed Modules by Types"
msgstr "Moduli Installati per Tipo"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_module__js_code_qty
msgid "JS Code Quantity"
msgstr "Quantità Codice JS"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author____last_update
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type____last_update
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule____last_update
msgid "Last Modified on"
msgstr "Ultima Modifica il"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__write_uid
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__write_uid
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__write_uid
msgid "Last Updated by"
msgstr "Ultimo aggiornamento di"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__write_date
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__write_date
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__write_date
msgid "Last Updated on"
msgstr "Ultimo aggiornamento il"
#. module: module_analysis
#: model:ir.model,name:module_analysis.model_ir_module_module
msgid "Module"
msgstr "Modulo"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__module_domain
msgid "Module Domain"
msgstr "Dominio Modulo"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_module__module_type_id
msgid "Module Type"
msgstr "Tipo Modulo"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__module_type_id
msgid "Module type"
msgstr "Tipo Modulo"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__installed_module_ids
msgid "Modules"
msgstr "Moduli"
#. module: module_analysis
#: model:ir.actions.act_window,name:module_analysis.action_ir_module_author
#: model:ir.model,name:module_analysis.model_ir_module_author
#: model:ir.ui.menu,name:module_analysis.menu_module_authors
msgid "Modules Authors"
msgstr "Autori Moduli"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__installed_module_qty
msgid "Modules Quantity"
msgstr "Quantità Moduli"
#. module: module_analysis
#: model:ir.actions.act_window,name:module_analysis.action_ir_module_type
#: model:ir.model,name:module_analysis.model_ir_module_type
#: model:ir.ui.menu,name:module_analysis.menu_module_types
msgid "Modules Types"
msgstr "Tipologia Moduli"
#. module: module_analysis
#: model:ir.actions.act_window,name:module_analysis.action_ir_module_type_rule
#: model:ir.model,name:module_analysis.model_ir_module_type_rule
#: model:ir.ui.menu,name:module_analysis.menu_module_type_rules
msgid "Modules Types Rules"
msgstr "Regole Tipologie Moduli"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__name
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__name
msgid "Name"
msgstr "Nome"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_module__python_code_qty
msgid "Python Code Quantity"
msgstr "Quantità Codice Python"
#. module: module_analysis
#: model_terms:ir.ui.view,arch_db:module_analysis.view_ir_module_module_form
msgid "Refresh Code Analysis"
msgstr "Aggiorna Analisi Codice"
#. module: module_analysis
#: model:ir.ui.menu,name:module_analysis.menu_module_analysis_reporting
msgid "Reporting"
msgstr "Resoconti"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__sequence
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__sequence
msgid "Sequence"
msgstr "Sequenza"
#. module: module_analysis
#: model:ir.ui.menu,name:module_analysis.menu_module_analysis_settings
msgid "Settings"
msgstr "Impostazioni"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__smart_search
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__smart_search
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__smart_search
msgid "Smart Search"
msgstr ""
#. module: module_analysis
#: model:ir.model.constraint,message:module_analysis.constraint_ir_module_author_name_uniq
msgid "The name of the modules author should be unique per database!"
msgstr "Il nome dell'autore del modulo deve essere unico nel database!"
#. module: module_analysis
#: model_terms:ir.ui.view,arch_db:module_analysis.view_ir_module_module_form
msgid "Type and Authors"
msgstr "Tipologia e Autori"
#. module: module_analysis
#: model:ir.model,name:module_analysis.model_base_module_update
msgid "Update Module"
msgstr "Aggiorna Modulo"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_module__xml_code_qty
msgid "XML Code Quantity"
msgstr "Quantità Codice XML"

View File

@ -0,0 +1,219 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * module_analysis
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 15.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_base_module_update__analyse_installed_modules
msgid "Analyse Installed Modules"
msgstr ""
#. module: module_analysis
#: model:ir.ui.menu,name:module_analysis.menu_module_analysis
msgid "Analysis"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_module__author_ids
msgid "Authors"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_module__css_code_qty
msgid "CSS Code Quantity"
msgstr ""
#. module: module_analysis
#: model_terms:ir.ui.view,arch_db:module_analysis.view_ir_module_module_form
msgid "Code Size"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__create_uid
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__create_uid
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__create_uid
msgid "Created by"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__create_date
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__create_date
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__create_date
msgid "Created on"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__display_name
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__display_name
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__display_name
msgid "Display Name"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__id
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__id
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__id
msgid "ID"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__installed_module_ids
msgid "Installed Modules"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__installed_module_qty
msgid "Installed Modules Quantity"
msgstr ""
#. module: module_analysis
#: model:ir.actions.act_window,name:module_analysis.action_ir_module_module_by_type
#: model:ir.ui.menu,name:module_analysis.menu_module_by_type
msgid "Installed Modules by Types"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_module__js_code_qty
msgid "JS Code Quantity"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author____last_update
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type____last_update
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule____last_update
msgid "Last Modified on"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__write_uid
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__write_uid
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__write_uid
msgid "Last Updated by"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__write_date
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__write_date
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__write_date
msgid "Last Updated on"
msgstr ""
#. module: module_analysis
#: model:ir.model,name:module_analysis.model_ir_module_module
msgid "Module"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__module_domain
msgid "Module Domain"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_module__module_type_id
msgid "Module Type"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__module_type_id
msgid "Module type"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__installed_module_ids
msgid "Modules"
msgstr ""
#. module: module_analysis
#: model:ir.actions.act_window,name:module_analysis.action_ir_module_author
#: model:ir.model,name:module_analysis.model_ir_module_author
#: model:ir.ui.menu,name:module_analysis.menu_module_authors
msgid "Modules Authors"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__installed_module_qty
msgid "Modules Quantity"
msgstr ""
#. module: module_analysis
#: model:ir.actions.act_window,name:module_analysis.action_ir_module_type
#: model:ir.model,name:module_analysis.model_ir_module_type
#: model:ir.ui.menu,name:module_analysis.menu_module_types
msgid "Modules Types"
msgstr ""
#. module: module_analysis
#: model:ir.actions.act_window,name:module_analysis.action_ir_module_type_rule
#: model:ir.model,name:module_analysis.model_ir_module_type_rule
#: model:ir.ui.menu,name:module_analysis.menu_module_type_rules
msgid "Modules Types Rules"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__name
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__name
msgid "Name"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_module__python_code_qty
msgid "Python Code Quantity"
msgstr ""
#. module: module_analysis
#: model_terms:ir.ui.view,arch_db:module_analysis.view_ir_module_module_form
msgid "Refresh Code Analysis"
msgstr ""
#. module: module_analysis
#: model:ir.ui.menu,name:module_analysis.menu_module_analysis_reporting
msgid "Reporting"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__sequence
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__sequence
msgid "Sequence"
msgstr ""
#. module: module_analysis
#: model:ir.ui.menu,name:module_analysis.menu_module_analysis_settings
msgid "Settings"
msgstr ""
#. module: module_analysis
#: model:ir.model.constraint,message:module_analysis.constraint_ir_module_author_name_uniq
msgid "The name of the modules author should be unique per database!"
msgstr ""
#. module: module_analysis
#: model_terms:ir.ui.view,arch_db:module_analysis.view_ir_module_module_form
msgid "Type and Authors"
msgstr ""
#. module: module_analysis
#: model:ir.model,name:module_analysis.model_base_module_update
msgid "Update Module"
msgstr ""
#. module: module_analysis
#: model:ir.actions.server,name:module_analysis.cron_module_analysis_ir_actions_server
#: model:ir.cron,cron_name:module_analysis.cron_module_analysis
#: model:ir.cron,name:module_analysis.cron_module_analysis
msgid "Update Module Analysis"
msgstr ""
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_module__xml_code_qty
msgid "XML Code Quantity"
msgstr ""

View File

@ -0,0 +1,222 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * module_analysis
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2019-08-31 06:51+0000\n"
"Last-Translator: 黎伟杰 <674416404@qq.com>\n"
"Language-Team: none\n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 3.8\n"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_base_module_update__analyse_installed_modules
msgid "Analyse Installed Modules"
msgstr "分析已安装的模块"
#. module: module_analysis
#: model:ir.ui.menu,name:module_analysis.menu_module_analysis
msgid "Analysis"
msgstr "分析"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_module__author_ids
msgid "Authors"
msgstr "作者"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_module__css_code_qty
msgid "CSS Code Quantity"
msgstr "CSS代码数量"
#. module: module_analysis
#: model_terms:ir.ui.view,arch_db:module_analysis.view_ir_module_module_form
msgid "Code Size"
msgstr "代码大小"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__create_uid
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__create_uid
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__create_uid
msgid "Created by"
msgstr "创建者"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__create_date
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__create_date
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__create_date
msgid "Created on"
msgstr "创建时间"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__display_name
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__display_name
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__display_name
msgid "Display Name"
msgstr "显示名称"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__id
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__id
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__id
msgid "ID"
msgstr "ID"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__installed_module_ids
msgid "Installed Modules"
msgstr "已安装的模块"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__installed_module_qty
msgid "Installed Modules Quantity"
msgstr "已安装的模块数量"
#. module: module_analysis
#: model:ir.actions.act_window,name:module_analysis.action_ir_module_module_by_type
#: model:ir.ui.menu,name:module_analysis.menu_module_by_type
msgid "Installed Modules by Types"
msgstr "按类型安装的模块"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_module__js_code_qty
msgid "JS Code Quantity"
msgstr "JS代码数量"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author____last_update
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type____last_update
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule____last_update
msgid "Last Modified on"
msgstr "最后修改时间"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__write_uid
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__write_uid
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__write_uid
msgid "Last Updated by"
msgstr "最后更新者"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__write_date
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__write_date
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__write_date
msgid "Last Updated on"
msgstr "最后更新时间"
#. module: module_analysis
#: model:ir.model,name:module_analysis.model_ir_module_module
msgid "Module"
msgstr "模块"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__module_domain
msgid "Module Domain"
msgstr "模块域"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_module__module_type_id
msgid "Module Type"
msgstr "模块类型"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__module_type_id
msgid "Module type"
msgstr "模块类型"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__installed_module_ids
msgid "Modules"
msgstr "模块"
#. module: module_analysis
#: model:ir.actions.act_window,name:module_analysis.action_ir_module_author
#: model:ir.model,name:module_analysis.model_ir_module_author
#: model:ir.ui.menu,name:module_analysis.menu_module_authors
msgid "Modules Authors"
msgstr "模块作者"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__installed_module_qty
msgid "Modules Quantity"
msgstr "模块数量"
#. module: module_analysis
#: model:ir.actions.act_window,name:module_analysis.action_ir_module_type
#: model:ir.model,name:module_analysis.model_ir_module_type
#: model:ir.ui.menu,name:module_analysis.menu_module_types
msgid "Modules Types"
msgstr "模块类型"
#. module: module_analysis
#: model:ir.actions.act_window,name:module_analysis.action_ir_module_type_rule
#: model:ir.model,name:module_analysis.model_ir_module_type_rule
#: model:ir.ui.menu,name:module_analysis.menu_module_type_rules
msgid "Modules Types Rules"
msgstr "模块类型规则"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__name
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__name
msgid "Name"
msgstr "名称"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_module__python_code_qty
msgid "Python Code Quantity"
msgstr "Python代码数量"
#. module: module_analysis
#: model_terms:ir.ui.view,arch_db:module_analysis.view_ir_module_module_form
msgid "Refresh Code Analysis"
msgstr "刷新代码分析"
#. module: module_analysis
#: model:ir.ui.menu,name:module_analysis.menu_module_analysis_reporting
msgid "Reporting"
msgstr "报告"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__sequence
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__sequence
msgid "Sequence"
msgstr "序列"
#. module: module_analysis
#: model:ir.ui.menu,name:module_analysis.menu_module_analysis_settings
msgid "Settings"
msgstr "设置"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_author__smart_search
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type__smart_search
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_type_rule__smart_search
msgid "Smart Search"
msgstr ""
#. module: module_analysis
#: model:ir.model.constraint,message:module_analysis.constraint_ir_module_author_name_uniq
msgid "The name of the modules author should be unique per database!"
msgstr "模块作者的名称应该是每个数据库唯一的!"
#. module: module_analysis
#: model_terms:ir.ui.view,arch_db:module_analysis.view_ir_module_module_form
msgid "Type and Authors"
msgstr "类型和作者"
#. module: module_analysis
#: model:ir.model,name:module_analysis.model_base_module_update
msgid "Update Module"
msgstr "更新模块"
#. module: module_analysis
#: model:ir.model.fields,field_description:module_analysis.field_ir_module_module__xml_code_qty
msgid "XML Code Quantity"
msgstr "XML代码数量"

View File

@ -0,0 +1,4 @@
from . import ir_module_author
from . import ir_module_module
from . import ir_module_type
from . import ir_module_type_rule

View File

@ -0,0 +1,45 @@
# 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).
from odoo import api, fields, models
class IrModuleAuthor(models.Model):
_name = "ir.module.author"
_description = "Modules Authors"
name = fields.Char(required=True)
installed_module_ids = fields.Many2many(
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,
)
_sql_constraints = [
(
"name_uniq",
"unique(name)",
"The name of the modules author should be unique per database!",
),
]
@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)])
if authors:
return authors[0]
else:
return self.create({"name": name})

View File

@ -0,0 +1,180 @@
# 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).
import logging
import os
from pathlib import Path
from pygount import SourceAnalysis
from odoo import api, fields, models
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"
author_ids = fields.Many2many(
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
)
python_code_qty = fields.Integer(string="Python 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)
css_code_qty = fields.Integer(string="CSS Code Quantity", readonly=True)
scss_code_qty = fields.Integer(string="SCSS Code Quantity", readonly=True)
# Overloadable Section
@api.model
def _get_analyse_settings(self):
"""Return a dictionnary of data analysed
Overload this function if you want to analyse other data
{
'extension': {
'data_to_analyse': 'field_name',
},
}, [...]
extension: extension of the file, with the '.'
data_to_analyse : possible value : code, documentation, empty, string
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"},
".scss": {"code": "scss_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,
"scss_code_qty": 0,
}
@api.model
def _get_module_encoding(self, file_ext):
return "utf-8"
def write(self, vals):
res = super().write(vals)
if 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
def button_analyse_code(self):
self._analyse_code()
@api.model
def cron_analyse_code(self, domain=None):
if domain is None:
domain = [("state", "=", "installed")]
self.search(domain)._analyse_code()
# Custom Section
def _analyse_code(self):
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()]
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] == "[":
author_txt_list = safe_eval(module.author)
else:
author_txt_list = (module.author and module.author.split(",")) or []
author_txt_list = [x.strip() for x in author_txt_list]
author_txt_list = [x for x in author_txt_list if x]
for author_txt in author_txt_list:
authors.append(IrModuleAuthor._get_or_create(author_txt))
author_ids = [x.id for x in authors]
module.author_ids = author_ids
# Update Module Type, based on rules
module_type_id = rules._get_module_type_id_from_module(module)
module.module_type_id = module_type_id
# Get Path of module folder and parse the code
module_path = get_module_path(module.name)
# Get Files
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
)
for file_path, file_ext in file_list:
file_res = SourceAnalysis.from_file(
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)
# Update the module with the datas
values = {}
for analyses in analysed_datas.values():
for v in analyses.values():
values[v["field"]] = v["value"]
module.write(values)
@api.model
def _get_files_to_analyse(
self, path, file_extensions, exclude_directories, exclude_files
):
res = []
if not path:
return res
for root, _, files in os.walk(path, followlinks=True):
if set(Path(root).parts) & set(exclude_directories):
continue
for name in files:
if name in exclude_files:
continue
filename, file_extension = os.path.splitext(name)
if file_extension in file_extensions:
res.append((os.path.join(root, name), file_extension))
return res
@api.model
def _get_analyse_data_dict(self):
res_dict = self._get_analyse_settings().copy()
for analyse_dict in res_dict.values():
for analyse_type, v in analyse_dict.items():
analyse_dict[analyse_type] = {"field": v, "value": 0}
return res_dict

View File

@ -0,0 +1,30 @@
# 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).
from odoo import api, fields, models
class IrModuleType(models.Model):
_name = "ir.module.type"
_description = "Modules Types"
_order = "sequence"
name = fields.Char(required=True)
sequence = fields.Integer()
installed_module_ids = fields.One2many(
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
)
@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)

View File

@ -0,0 +1,29 @@
# 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).
from odoo import fields, models
from odoo.tools.safe_eval import safe_eval
class IrModuleType(models.Model):
_name = "ir.module.type.rule"
_description = "Modules Types Rules"
_order = "sequence"
sequence = fields.Integer()
module_domain = fields.Char(required=True, default="[]")
module_type_id = fields.Many2one(
string="Module type", comodel_name="ir.module.type", required=True
)
def _get_module_type_id_from_module(self, module):
IrModuleModule = self.env["ir.module.module"]
for rule in self:
domain = safe_eval(rule.module_domain)
domain.append(("id", "=", module.id))
if IrModuleModule.search(domain):
return rule.module_type_id.id
return False

View File

@ -0,0 +1,65 @@
* Go to Apps / Module Analysis / Modules Types Rules
The Module types Rules are usefull to get the Type of a module, based on
it information.
This module comes with default rules.
.. image:: ../static/description/default_module_type_rules.png
You can add your custom rules to identify the modules your team have
developped for exemple,
.. image:: ../static/description/add_module_type_rules.png
to update the data manually, you have to :
* Go to 'Settings' / 'Technical' / 'Scheduled Actions'
* Run manually the action : 'Update Module Analysis'
This will update analysis of your installed modules.
to update the data automatically, you have to :
* Go to 'Settings' / 'Technical' / 'Scheduled Actions'
* Configure the action 'Update Module Analysis' and activate it. (By default, the cron is unactive and no analysis is done)
Adding Extra data
~~~~~~~~~~~~~~~~~
If you want to analyse other data, (for exemple, having the number of HTML
files), create a custom modules and overload the module model :
.. code-block:: python
from odoo import api, fields, models
class IrModuleModule(models.Model):
_inherit = 'ir.module.module'
xml_documentation_qty = fields.Integer(
string='Quantity of Comments in XML Files')
@api.model
def _get_analyse_settings(self):
res = super()._get_analyse_settings()
if not '.html' in res:
res['.html'] = {}
res['.html']['documentation'] 'xml_documentation_qty'
return res
Exclude files and directories
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Two parameters are availaible in 'Settings' / 'Technical' / 'Parameters'
'System Parameters' :
.. image:: ../static/description/config_parameters.png
The list of folders and filename will be exclude from the analysis.
You can change the default settings.

View File

@ -0,0 +1 @@
* Sylvain LE GAL (https://twitter.com/legalsylvain)

View File

@ -0,0 +1,26 @@
This module allows you to know 'how much code' is running on your Odoo
instance, group by 'Type' (Odoo Core, OCA, other...)
This module can be usefull in the following cases :
* To analyse the size of your technical debt, regarding your Custom modules
* To know the ratio between Odoo / OCA and Custom modules
* To evaluate the amount to pay to odoo to upgrade your custom code, or the
induced workload
.. image:: ../static/description/installed_modules_by_types.png
For that purpose, it adds new concepts
* ``ir.module.author``, based on the value ``author`` present in the manifest
file.
.. image:: ../static/description/module_authors.png
* ``ir.module.type``, populated by default with Odoo and OCA values.
.. image:: ../static/description/module_types.png
Each installed modules have extra data in the 'Technical Data' tab :
.. image:: ../static/description/module_form.png

View File

@ -0,0 +1,3 @@
To use this module, you have to install the ``pygount`` python librairy.
``pip install pygount``

View File

@ -0,0 +1,7 @@
* Go to 'Apps' / 'Module Analysis' / 'Installed module by Types'
Open the stats to analyse the detail of the code installed
.. image:: ../static/description/analysis_pivot.png
.. image:: ../static/description/analysis_pie.png

View File

@ -0,0 +1,4 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_ir_module_author_manager,ir_module_author_manager,model_ir_module_author,base.group_system,1,1,1,1
access_ir_module_type_manager,ir_module_type_manager,model_ir_module_type,base.group_system,1,1,1,1
access_ir_module_type_rule_manager,ir_module_type_rule_manager,model_ir_module_type_rule,base.group_system,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_ir_module_author_manager ir_module_author_manager model_ir_module_author base.group_system 1 1 1 1
3 access_ir_module_type_manager ir_module_type_manager model_ir_module_type base.group_system 1 1 1 1
4 access_ir_module_type_rule_manager ir_module_type_rule_manager model_ir_module_type_rule base.group_system 1 1 1 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@ -0,0 +1,528 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.15.1: http://docutils.sourceforge.net/" />
<title>Module Analysis</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="module-analysis">
<h1 class="title">Module Analysis</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/server-tools/tree/15.0/module_analysis"><img alt="OCA/server-tools" src="https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/server-tools-15-0/server-tools-15-0-module_analysis"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/149/15.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module allows you to know how much code is running on your Odoo
instance, group by Type (Odoo Core, OCA, other…)</p>
<p>This module can be usefull in the following cases :</p>
<ul class="simple">
<li>To analyse the size of your technical debt, regarding your Custom modules</li>
<li>To know the ratio between Odoo / OCA and Custom modules</li>
<li>To evaluate the amount to pay to odoo to upgrade your custom code, or the
induced workload</li>
</ul>
<img alt="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/installed_modules_by_types.png" src="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/installed_modules_by_types.png" />
<p>For that purpose, it adds new concepts</p>
<ul class="simple">
<li><tt class="docutils literal">ir.module.author</tt>, based on the value <tt class="docutils literal">author</tt> present in the manifest
file.</li>
</ul>
<img alt="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/module_authors.png" src="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/module_authors.png" />
<ul class="simple">
<li><tt class="docutils literal">ir.module.type</tt>, populated by default with Odoo and OCA values.</li>
</ul>
<img alt="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/module_types.png" src="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/module_types.png" />
<p>Each installed modules have extra data in the Technical Data tab :</p>
<img alt="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/module_form.png" src="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/module_form.png" />
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#installation" id="id1">Installation</a></li>
<li><a class="reference internal" href="#configuration" id="id2">Configuration</a><ul>
<li><a class="reference internal" href="#adding-extra-data" id="id3">Adding Extra data</a></li>
<li><a class="reference internal" href="#exclude-files-and-directories" id="id4">Exclude files and directories</a></li>
</ul>
</li>
<li><a class="reference internal" href="#usage" id="id5">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id6">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id7">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id8">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id9">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id10">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="installation">
<h1><a class="toc-backref" href="#id1">Installation</a></h1>
<p>To use this module, you have to install the <tt class="docutils literal">pygount</tt> python librairy.</p>
<p><tt class="docutils literal">pip install pygount</tt></p>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#id2">Configuration</a></h1>
<ul class="simple">
<li>Go to Apps / Module Analysis / Modules Types Rules</li>
</ul>
<p>The Module types Rules are usefull to get the Type of a module, based on
it information.</p>
<p>This module comes with default rules.</p>
<blockquote>
<img alt="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/default_module_type_rules.png" src="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/default_module_type_rules.png" />
</blockquote>
<p>You can add your custom rules to identify the modules your team have
developped for exemple,</p>
<blockquote>
<img alt="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/add_module_type_rules.png" src="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/add_module_type_rules.png" />
</blockquote>
<p>to update the data manually, you have to :</p>
<ul>
<li><p class="first">Go to Apps / Update Apps List</p>
</li>
<li><p class="first">Check the box Analyse Installed modules</p>
<blockquote>
<img alt="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/base_module_update.png" src="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/base_module_update.png" />
</blockquote>
</li>
</ul>
<p>This will update analysis of your installed modules.</p>
<p>to update the data automatically, you have to :</p>
<ul class="simple">
<li>Go to Settings / Technical / Scheduled Actions</li>
<li>Configure the action Update Module Analysis. (By default, the analysis will be done nightly)</li>
</ul>
<div class="section" id="adding-extra-data">
<h2><a class="toc-backref" href="#id3">Adding Extra data</a></h2>
<p>If you want to analyse other data, (for exemple, having the number of HTML
files), create a custom modules and overload the module model :</p>
<pre class="code python literal-block">
<span class="kn">from</span> <span class="nn">odoo</span> <span class="kn">import</span> <span class="n">api</span><span class="p">,</span> <span class="n">fields</span><span class="p">,</span> <span class="n">models</span>
<span class="k">class</span> <span class="nc">IrModuleModule</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="n">_inherit</span> <span class="o">=</span> <span class="s1">'ir.module.module'</span>
<span class="n">xml_documentation_qty</span> <span class="o">=</span> <span class="n">fields</span><span class="o">.</span><span class="n">Integer</span><span class="p">(</span>
<span class="n">string</span><span class="o">=</span><span class="s1">'Quantity of Comments in XML Files'</span><span class="p">)</span>
<span class="nd">&#64;api</span><span class="o">.</span><span class="n">model</span>
<span class="k">def</span> <span class="nf">_get_analyse_settings</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">res</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">_get_analyse_settings</span><span class="p">()</span>
<span class="k">if</span> <span class="ow">not</span> <span class="s1">'.html'</span> <span class="ow">in</span> <span class="n">res</span><span class="p">:</span>
<span class="n">res</span><span class="p">[</span><span class="s1">'.html'</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">res</span><span class="p">[</span><span class="s1">'.html'</span><span class="p">][</span><span class="s1">'documentation'</span><span class="p">]</span> <span class="s1">'xml_documentation_qty'</span>
<span class="k">return</span> <span class="n">res</span>
</pre>
</div>
<div class="section" id="exclude-files-and-directories">
<h2><a class="toc-backref" href="#id4">Exclude files and directories</a></h2>
<p>Two parameters are availaible in Settings / Technical / Parameters
System Parameters :</p>
<blockquote>
<img alt="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/config_parameters.png" src="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/config_parameters.png" />
</blockquote>
<p>The list of folders and filename will be exclude from the analysis.
You can change the default settings.</p>
</div>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id5">Usage</a></h1>
<ul class="simple">
<li>Go to Apps / Module Analysis / Installed module by Types</li>
</ul>
<p>Open the stats to analyse the detail of the code installed</p>
<blockquote>
<img alt="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/analysis_pivot.png" src="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/analysis_pivot.png" />
<img alt="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/analysis_pie.png" src="https://raw.githubusercontent.com/OCA/server-tools/15.0/module_analysis/static/description/analysis_pie.png" />
</blockquote>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id6">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/server-tools/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/server-tools/issues/new?body=module:%20module_analysis%0Aversion:%2015.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#id7">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id8">Authors</a></h2>
<ul class="simple">
<li>GRAP</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id9">Contributors</a></h2>
<ul class="simple">
<li>Sylvain LE GAL (<a class="reference external" href="https://twitter.com/legalsylvain">https://twitter.com/legalsylvain</a>)</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id10">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>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.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/server-tools/tree/15.0/module_analysis">OCA/server-tools</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1 @@
from . import test_module

View File

@ -0,0 +1,34 @@
# 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).
from odoo.tests.common import TransactionCase
class TestModule(TransactionCase):
def setUp(self):
super().setUp()
self.IrModuleModule = self.env["ir.module.module"]
def test_installed_modules(self):
self.IrModuleModule.cron_analyse_code()
installed_modules = self.IrModuleModule.search(
[("state", "=", "installed"), ("name", "not like", "_test")]
)
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 '%s' doesn't have code analysed defined, whereas it is"
" installed." % (module.name),
)
def test_uninstalled_modules(self):
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),
)

View File

@ -0,0 +1,27 @@
<?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"
name="Analysis"
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"
name="Reporting"
parent="menu_module_analysis"
sequence="20"
/>
</odoo>

View File

@ -0,0 +1,50 @@
<?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>
<group>
<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" />
</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>
<field name="res_model">ir.module.author</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem
id="menu_module_authors"
parent="menu_module_analysis_settings"
sequence="1"
action="action_ir_module_author"
groups="base.group_no_one"
/>
</odoo>

View File

@ -0,0 +1,69 @@
<?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="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"
/>
<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="scss_code_qty" />
</group>
<group string="Type and Authors">
<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="scss_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" />
</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>
<field name="res_model">ir.module.module</field>
<field name="domain">[('state', '=', 'installed')]</field>
<field name="view_mode">pivot,graph</field>
</record>
<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"
/>
</odoo>

View File

@ -0,0 +1,49 @@
<?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>
<group>
</group>
</sheet>
</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" />
</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>
<field name="res_model">ir.module.type</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem
id="menu_module_types"
parent="menu_module_analysis_settings"
sequence="2"
action="action_ir_module_type"
groups="base.group_no_one"
/>
</odoo>

View File

@ -0,0 +1,31 @@
<?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" />
</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>
<field name="res_model">ir.module.type.rule</field>
<field name="view_mode">tree</field>
</record>
<menuitem
id="menu_module_type_rules"
parent="menu_module_analysis_settings"
sequence="3"
action="action_ir_module_type_rule"
groups="base.group_no_one"
/>
</odoo>

View File

@ -5,4 +5,5 @@ mako
odoorpc
openpyxl
openupgradelib
pygount
sentry_sdk>=1.17.0

View File

@ -0,0 +1 @@
../../../../module_analysis

View File

@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)