Merge branch 'dev_1.2.2'

- Update to python 3.7.12
- Security update
- New repo like themes
- Improve test for code generator
This commit is contained in:
Mathieu Benoit 2022-01-24 14:10:49 -05:00
commit fcc94e1822
67 changed files with 7272 additions and 1024 deletions

4
.gitignore vendored
View file

@ -10,7 +10,9 @@ config.conf
*.pyc
.repo
addons
!addons/
addons/*
!script/addons
doc/itpp*
doc/odoo*
script/OCA*

View file

@ -1 +1 @@
3.7.7
3.7.12

302
Makefile
View file

@ -1,4 +1,5 @@
SHELL := /bin/bash
LOG_FILE := ./.venv/make_test.log
#############
# General #
#############
@ -112,6 +113,10 @@ db_drop_db_code_generator:
db_drop_db_template:
./.venv/bin/python3 ./odoo/odoo-bin db --drop --database template
.PHONY: db_drop_all
db_drop_all:
./script/database/db_drop_all.py
.PHONY: db_clean_cache
db_clean_cache:
./script/db_restore.py --clean_cache
@ -121,7 +126,8 @@ db_restore_erplibre_base_db_test:
./script/db_restore.py --database test
.PHONY: db_restore_erplibre_base_db_test_module_test
db_restore_erplibre_base_db_test_module_test: db_restore_erplibre_base_db_test
db_restore_erplibre_base_db_test_module_test:
./script/make.sh db_restore_erplibre_base_db_test
./script/addons/install_addons.sh test test
.PHONY: db_restore_erplibre_base_db_test_image_test
@ -157,7 +163,8 @@ db_restore_erplibre_base_db_template:
./script/db_restore.py --database template
.PHONY: db_create_db_test
db_create_db_test: db_drop_db_test
db_create_db_test:
./script/make.sh db_drop_db_test
./.venv/bin/python3 ./odoo/odoo-bin db --create --database test
########################
@ -166,7 +173,7 @@ db_create_db_test: db_drop_db_test
.PHONY: image_db_create_erplibre_base
image_db_create_erplibre_base:
./script/make.sh db_create_db_test
./script/addons/install_addons.sh test web_responsive,disable_odoo_online,remove_odoo_enterprise,auth_user_case_insensitive,muk_web_theme,muk_utils,muk_branding,muk_mail_branding,muk_web_branding,muk_web_theme_mail,muk_web_utils,fetchmail_notify_error_to_sender,mail_debrand,partner_quebec_tz,erplibre_info
./script/addons/install_addons.sh test web_responsive,disable_odoo_online,remove_odoo_enterprise,auth_user_case_insensitive,muk_web_theme,muk_utils,muk_branding,muk_mail_branding,muk_web_branding,muk_web_theme_mail,muk_web_utils,fetchmail_notify_error_to_sender,mail_debrand,partner_quebec_tz,erplibre_info,web_timeline,web_diagram_position
./.venv/bin/python3 ./odoo/odoo-bin db --backup --database test --restore_image erplibre_base
.PHONY: image_db_create_erplibre_website
@ -216,15 +223,18 @@ image_diff_base_website:
# Addons installation #
#########################
.PHONY: addons_install_code_generator_basic
addons_install_code_generator_basic: db_restore_erplibre_base_db_code_generator
addons_install_code_generator_basic:
./script/make.sh db_restore_erplibre_base_db_code_generator
./script/addons/install_addons_dev.sh code_generator code_generator
.PHONY: addons_install_code_generator_featured
addons_install_code_generator_featured: db_restore_erplibre_base_db_code_generator
addons_install_code_generator_featured:
./script/make.sh db_restore_erplibre_base_db_code_generator
./script/addons/install_addons_dev.sh code_generator code_generator_cron,code_generator_hook,code_generator_portal
.PHONY: addons_install_code_generator_full
addons_install_code_generator_full: db_restore_erplibre_base_db_code_generator
addons_install_code_generator_full:
./script/make.sh db_restore_erplibre_base_db_code_generator
./script/addons/install_addons_dev.sh code_generator code_generator_cron,code_generator_hook,code_generator_portal,code_generator_db_servers,code_generator_website_snippet,code_generator_geoengine,code_generator_theme_website,code_generator_website_leaflet
.PHONY: addons_install_code_generator_demo
@ -236,27 +246,40 @@ addons_uninstall_code_generator_demo:
./script/addons/uninstall_addons.sh code_generator code_generator_demo
.PHONY: addons_reinstall_code_generator_demo
addons_reinstall_code_generator_demo: addons_uninstall_code_generator_demo addons_install_code_generator_demo
addons_reinstall_code_generator_demo:
./script/make.sh addons_uninstall_code_generator_demo
./script/make.sh addons_install_code_generator_demo
.PHONY: addons_install_all_code_generator_demo
addons_install_all_code_generator_demo: db_restore_erplibre_base_db_code_generator
./script/addons/install_addons_dev.sh code_generator code_generator_demo,code_generator_demo_export_helpdesk,code_generator_demo_internal,code_generator_demo_portal,code_generator_demo_theme_website,code_generator_demo_website_leaflet,code_generator_demo_website_snippet
addons_install_all_code_generator_demo:
./script/make.sh db_restore_erplibre_base_db_code_generator
./script/addons/install_addons_dev.sh code_generator code_generator_demo,code_generator_demo_export_helpdesk,code_generator_demo_internal,code_generator_demo_internal_inherit,code_generator_demo_portal,code_generator_demo_theme_website,code_generator_demo_website_leaflet,code_generator_demo_website_snippet,code_generator_auto_backup
# ./script/addons/install_addons_dev.sh code_generator code_generator_demo
# ./script/addons/install_addons_dev.sh code_generator code_generator_demo_export_helpdesk
# ./script/addons/install_addons_dev.sh code_generator code_generator_demo_internal
# ./script/addons/install_addons_dev.sh code_generator code_generator_demo_internal_inherit
# ./script/addons/install_addons_dev.sh code_generator code_generator_demo_portal
# ./script/addons/install_addons_dev.sh code_generator code_generator_auto_backup
# ./script/addons/install_addons_dev.sh code_generator code_generator_demo_theme_website
# ./script/addons/install_addons_dev.sh code_generator code_generator_demo_website_leaflet
# ./script/addons/install_addons_dev.sh code_generator code_generator_demo_website_snippet
.PHONY: addons_install_all_code_generator_template
addons_install_all_code_generator_template:
./script/addons/install_addons_dev.sh template demo_portal,auto_backup
./script/addons/install_addons_dev.sh template code_generator_template_demo_portal code_generator_template_demo_sysadmin_cron
./script/make.sh db_restore_erplibre_base_db_template
./script/addons/install_addons_dev.sh template demo_portal,auto_backup,demo_internal_inherit
./script/addons/install_addons_dev.sh template code_generator_template_demo_portal,code_generator_template_demo_sysadmin_cron,code_generator_template_demo_internal_inherit
#./script/addons/install_addons_dev.sh template demo_portal
#./script/addons/install_addons_dev.sh template code_generator_template_demo_portal
#./script/addons/install_addons_dev.sh template auto_backup
#./script/addons/install_addons_dev.sh template code_generator_template_demo_sysadmin_cron
#./script/addons/install_addons_dev.sh template demo_internal_inherit
#./script/addons/install_addons_dev.sh template code_generator_template_demo_internal_inherit
.PHONY: addons_install_all_generated_demo
addons_install_all_generated_demo:
./script/addons/install_addons_dev.sh template demo_export_helpdesk,demo_internal,demo_portal,demo_website_leaflet,demo_website_snippet
./script/make.sh db_restore_erplibre_base_db_template
./script/addons/install_addons_dev.sh template demo_helpdesk_data,demo_internal,demo_internal_inherit,demo_portal,demo_website_leaflet,demo_website_snippet,auto_backup
# TODO support installation theme with cli
#./script/addons/install_addons_dev.sh template theme_website_demo_code_generator
@ -264,51 +287,196 @@ addons_install_all_generated_demo:
addons_install_all_code_generator:
./script/addons/install_addons_dev.sh code_generator code_generator_auto_backup
##################
# Code generator #
##################
.PHONY: addons_install_code_generator_template_code_generator
addons_install_code_generator_template_code_generator:
./script/db_restore.py --database template
./script/code_generator/search_class_model.py --quiet -d addons/TechnoLibre_odoo-code-generator/code_generator -t addons/TechnoLibre_odoo-code-generator-template/code_generator_template_code_generator --with_inherit
./script/maintenance/black.sh ./addons/TechnoLibre_odoo-code-generator-template/code_generator_template_code_generator
./script/addons/install_addons_dev.sh template code_generator
./script/addons/install_addons_dev.sh template code_generator_template_code_generator
./script/git/remote_code_generation_git_compare.py --quiet --git_gui --clear --replace_directory --directory1 ./addons/TechnoLibre_odoo-code-generator-template/code_generator_code_generator --directory2 ./addons/TechnoLibre_odoo-code-generator/code_generator_code_generator
.PHONY: addons_install_code_generator_code_generator
addons_install_code_generator_code_generator:
./script/db_restore.py --database code_generator
./script/addons/install_addons_dev.sh code_generator code_generator_code_generator
./script/git/remote_code_generation_git_compare.py --quiet --git_gui --clear --replace_directory --directory1 ./addons/TechnoLibre_odoo-code-generator/code_generator --directory2 ./addons/TechnoLibre_odoo-code-generator-template/code_generator
.PHONY: meld_code_generator_template_code_generator
meld_code_generator_template_code_generator:
./script/make.sh clean
meld ./addons/TechnoLibre_odoo-code-generator/code_generator_code_generator ./addons/TechnoLibre_odoo-code-generator-template/code_generator_code_generator
.PHONY: meld_code_generator_code_generator
meld_code_generator_code_generator:
./script/make.sh clean
meld ./addons/TechnoLibre_odoo-code-generator-template/code_generator ./addons/TechnoLibre_odoo-code-generator/code_generator
########################
# Extra migrator sql #
########################
.PHONY: addons_install_code_generator_mariadb_sql_example_1
addons_install_code_generator_mariadb_sql_example_1:
./script/database/restore_mariadb_sql_example_1.sh
./script/db_restore.py --database code_generator
./script/addons/install_addons_dev.sh code_generator code_generator_portal
./script/addons/install_addons_dev.sh code_generator code_generator_migrator_demo_mariadb_sql_example_1
./script/db_restore.py --database template
./script/addons/install_addons_dev.sh template code_generator_portal,demo_mariadb_sql_example_1
./script/code_generator/search_class_model.py --quiet -d addons/TechnoLibre_odoo-code-generator-template/demo_mariadb_sql_example_1 -t addons/TechnoLibre_odoo-code-generator-template/code_generator_template_demo_mariadb_sql_example_1
./script/addons/install_addons_dev.sh template code_generator_template_demo_mariadb_sql_example_1
./script/db_restore.py --database code_generator
./script/addons/install_addons_dev.sh code_generator code_generator_portal
./script/addons/install_addons_dev.sh code_generator code_generator_demo_mariadb_sql_example_1
##########
# test #
##########
.PHONY: test
test: test_format test_code_generator_generation test_code_generator_generation_extra test_code_generator_code_i18n test_code_generator_code_i18n_extra
test:
./script/make.sh clean
-rm ${LOG_FILE}
./script/make.sh test_base |& tee -a ${LOG_FILE}
./script/test/check_result_test.sh ${LOG_FILE}
.PHONY: test_full
test_full:
./script/make.sh clean
-rm ${LOG_FILE}
./script/make.sh test_base |& tee -a ${LOG_FILE}
./script/make.sh test_extra |& tee -a ${LOG_FILE}
#./script/make.sh doc |& tee -a ${LOG_FILE}
./script/test/check_result_test.sh ${LOG_FILE}
.PHONY: test_full_fast
test_full_fast:
./script/make.sh clean
./script/test/run_parallel_test.py
.PHONY: test_base
test_base:
./script/make.sh test_format
./script/make.sh test_code_generator_hello_world
./script/make.sh test_installation_demo
./script/make.sh test_code_generator_generation
./script/make.sh test_code_generator_generation_template
.PHONY: test_extra
test_extra:
./script/make.sh test_code_generator_migrator_demo_mariadb_sql_example_1
./script/make.sh test_code_generator_template_demo_mariadb_sql_example_1
./script/make.sh test_code_generator_demo_mariadb_sql_example_1
.PHONY: test_format
test_format:
./script/maintenance/black.sh --check ./addons/TechnoLibre_odoo-code-generator/
./script/maintenance/black.sh --check ./addons/TechnoLibre_odoo-code-generator-template/
.PHONY: test_code_generator_hello_world
test_code_generator_hello_world:
./test/code_generator/hello_world.sh
.PHONY: test_installation_demo
test_installation_demo:
./script/code_generator/check_git_change_code_generator.sh ./addons/TechnoLibre_odoo-code-generator-template
./script/db_restore.py --database test_demo
./script/addons/install_addons.sh test_demo demo_helpdesk_data,demo_internal,demo_internal_inherit,demo_mariadb_sql_example_1,demo_portal,demo_website_data,demo_website_leaflet,demo_website_snippet
# TODO cannot install from command line (CLI)
#./script/addons/install_addons.sh test_demo theme_website_demo_code_generator ./addons/TechnoLibre_odoo-code-generator-template
.PHONY: test_code_generator_generation
test_code_generator_generation:
./script/code_generator/check_git_change_code_generator.sh ./addons/TechnoLibre_odoo-code-generator-template
./script/db_restore.py --database code_generator
./script/code_generator/install_and_test_code_generator.sh code_generator code_generator_demo,code_generator_demo_export_helpdesk,code_generator_demo_internal,code_generator_demo_portal,code_generator_demo_theme_website,code_generator_demo_website_leaflet,code_generator_demo_website_snippet ./addons/TechnoLibre_odoo-code-generator-template
# ./script/code_generator/install_and_test_code_generator.sh code_generator code_generator_demo ./addons/TechnoLibre_odoo-code-generator-template
# ./script/code_generator/install_and_test_code_generator.sh code_generator code_generator_demo_export_helpdesk ./addons/TechnoLibre_odoo-code-generator-template
# ./script/code_generator/install_and_test_code_generator.sh code_generator code_generator_demo_internal ./addons/TechnoLibre_odoo-code-generator-template
# ./script/code_generator/install_and_test_code_generator.sh code_generator code_generator_demo_portal ./addons/TechnoLibre_odoo-code-generator-template
# ./script/code_generator/install_and_test_code_generator.sh code_generator code_generator_demo_theme_website ./addons/TechnoLibre_odoo-code-generator-template
# ./script/code_generator/install_and_test_code_generator.sh code_generator code_generator_demo_website_leaflet ./addons/TechnoLibre_odoo-code-generator-template
# ./script/code_generator/install_and_test_code_generator.sh code_generator code_generator_demo_website_snippet ./addons/TechnoLibre_odoo-code-generator-template
.PHONY: test_code_generator_generation_extra
test_code_generator_generation_extra:
./script/code_generator/check_git_change_code_generator.sh ./addons/OCA_server-tools/auto_backup
./script/db_restore.py --database code_generator
./script/code_generator/install_and_test_code_generator.sh code_generator code_generator_auto_backup ./addons/OCA_server-tools/auto_backup
# Multiple
./script/db_restore.py --database test_code_generator
./script/code_generator/install_and_test_code_generator.sh test_code_generator code_generator_demo,code_generator_demo_export_helpdesk,code_generator_demo_export_website,code_generator_demo_internal,code_generator_demo_portal,code_generator_demo_theme_website,code_generator_demo_website_leaflet,code_generator_demo_website_snippet ./addons/TechnoLibre_odoo-code-generator-template code_generator_demo,demo_helpdesk_data,demo_website_data,demo_internal,demo_portal,theme_website_demo_code_generator,demo_website_leaflet,demo_website_snippet
# inherit
# TODO should be in multiple list, need to support it
./script/db_restore.py --database test_code_generator
./script/code_generator/install_and_test_code_generator.sh test_code_generator code_generator_demo_internal_inherit ./addons/TechnoLibre_odoo-code-generator-template demo_internal_inherit
# auto_backup
./script/db_restore.py --database test_code_generator
./script/code_generator/install_and_test_code_generator.sh test_code_generator code_generator_auto_backup ./addons/OCA_server-tools/auto_backup auto_backup
.PHONY: test_code_generator_code_i18n
test_code_generator_code_i18n:
# Single
#./script/db_restore.py --database test_code_generator
#./script/code_generator/install_and_test_code_generator.sh test_code_generator code_generator_demo ./addons/TechnoLibre_odoo-code-generator-template code_generator_demo
#./script/code_generator/install_and_test_code_generator.sh test_code_generator code_generator_demo_export_helpdesk ./addons/TechnoLibre_odoo-code-generator-template demo_helpdesk_data
#./script/code_generator/install_and_test_code_generator.sh test_code_generator code_generator_demo_export_website ./addons/TechnoLibre_odoo-code-generator-template demo_website_data
#./script/code_generator/install_and_test_code_generator.sh test_code_generator code_generator_demo_internal ./addons/TechnoLibre_odoo-code-generator-template demo_internal
#./script/code_generator/install_and_test_code_generator.sh test_code_generator code_generator_demo_portal ./addons/TechnoLibre_odoo-code-generator-template demo_portal
#./script/code_generator/install_and_test_code_generator.sh test_code_generator code_generator_demo_theme_website ./addons/TechnoLibre_odoo-code-generator-template theme_website_demo_code_generator
#./script/code_generator/install_and_test_code_generator.sh test_code_generator code_generator_demo_website_leaflet ./addons/TechnoLibre_odoo-code-generator-template demo_website_leaflet
#./script/code_generator/install_and_test_code_generator.sh test_code_generator code_generator_demo_website_snippet ./addons/TechnoLibre_odoo-code-generator-template demo_website_snippet
#./script/db_restore.py --database test_code_generator
#./script/code_generator/install_and_test_code_generator.sh test_code_generator code_generator_demo_internal_inherit ./addons/TechnoLibre_odoo-code-generator-template demo_internal_inherit
#./script/db_restore.py --database test_code_generator
#./script/code_generator/install_and_test_code_generator.sh test_code_generator code_generator_auto_backup ./addons/OCA_server-tools/auto_backup auto_backup
.PHONY: test_code_generator_generation_template
test_code_generator_generation_template:
./script/make.sh test_code_generator_code_template_demo_portal
./script/make.sh test_code_generator_code_template_demo_internal_inherit
./script/make.sh test_code_generator_code_template_demo_sysadmin_cron
.PHONY: test_code_generator_code_template_demo_portal
test_code_generator_code_template_demo_portal:
./script/code_generator/check_git_change_code_generator.sh ./addons/TechnoLibre_odoo-code-generator-template
./script/db_restore.py --database template
./script/addons/install_addons_dev.sh template demo_portal
./script/code_generator/install_and_test_code_generator.sh template code_generator_template_demo_portal ./addons/TechnoLibre_odoo-code-generator-template
./script/db_restore.py --database test_template
./script/addons/install_addons_dev.sh test_template demo_portal
#./script/addons/install_addons_dev.sh test_template code_generator_template_demo_portal
./script/code_generator/search_class_model.py --quiet -d addons/TechnoLibre_odoo-code-generator-template/demo_portal -t addons/TechnoLibre_odoo-code-generator-template/code_generator_template_demo_portal --with_inherit
./script/code_generator/install_and_test_code_generator.sh test_template code_generator_template_demo_portal ./addons/TechnoLibre_odoo-code-generator-template code_generator_demo_portal
.PHONY: test_code_generator_code_i18n_extra
test_code_generator_code_i18n_extra:
./script/code_generator/check_git_change_code_generator.sh ./addons/OCA_server-tools/auto_backup
./script/db_restore.py --database template
./script/addons/install_addons_dev.sh template auto_backup
./script/code_generator/install_and_test_code_generator.sh template code_generator_template_demo_sysadmin_cron ./addons/TechnoLibre_odoo-code-generator-template
# To support i18n in auto_backup
.PHONY: test_code_generator_code_template_demo_internal_inherit
test_code_generator_code_template_demo_internal_inherit:
./script/code_generator/check_git_change_code_generator.sh ./addons/TechnoLibre_odoo-code-generator-template
./script/db_restore.py --database test_template
./script/addons/install_addons_dev.sh test_template demo_internal_inherit
#./script/addons/install_addons_dev.sh test_template code_generator_template_demo_internal_inherit
./script/code_generator/search_class_model.py --quiet -d addons/TechnoLibre_odoo-code-generator-template/demo_internal_inherit -t addons/TechnoLibre_odoo-code-generator-template/code_generator_template_demo_internal_inherit --with_inherit
./script/code_generator/install_and_test_code_generator.sh test_template code_generator_template_demo_internal_inherit ./addons/TechnoLibre_odoo-code-generator-template code_generator_demo_internal_inherit
.PHONY: test_code_generator_code_template_demo_sysadmin_cron
test_code_generator_code_template_demo_sysadmin_cron:
./script/code_generator/check_git_change_code_generator.sh ./addons/OCA_server-tools/auto_backup
./script/db_restore.py --database test_template
./script/addons/install_addons_dev.sh test_template auto_backup
#./script/addons/install_addons_dev.sh test_template code_generator_template_demo_sysadmin_cron
./script/code_generator/search_class_model.py --quiet -d addons/OCA_server-tools/auto_backup -t addons/TechnoLibre_odoo-code-generator-template/code_generator_template_demo_sysadmin_cron --with_inherit
./script/code_generator/install_and_test_code_generator.sh test_template code_generator_template_demo_sysadmin_cron ./addons/TechnoLibre_odoo-code-generator-template code_generator_auto_backup
.PHONY: test_code_generator_migrator_demo_mariadb_sql_example_1
test_code_generator_migrator_demo_mariadb_sql_example_1:
./script/code_generator/check_git_change_code_generator.sh ./addons/TechnoLibre_odoo-code-generator-template
./script/database/restore_mariadb_sql_example_1.sh
./script/db_restore.py --database test_code_generator
./script/addons/install_addons_dev.sh test_code_generator code_generator_portal
#./script/addons/install_addons_dev.sh test_code_generator code_generator_migrator_demo_mariadb_sql_example_1
./script/code_generator/install_and_test_code_generator.sh test_code_generator code_generator_migrator_demo_mariadb_sql_example_1 ./addons/TechnoLibre_odoo-code-generator-template demo_mariadb_sql_example_1
.PHONY: test_code_generator_template_demo_mariadb_sql_example_1
test_code_generator_template_demo_mariadb_sql_example_1:
./script/code_generator/check_git_change_code_generator.sh ./addons/TechnoLibre_odoo-code-generator-template
./script/db_restore.py --database test_template
./script/addons/install_addons_dev.sh test_template code_generator_portal,demo_mariadb_sql_example_1
./script/code_generator/search_class_model.py --quiet -d addons/TechnoLibre_odoo-code-generator-template/demo_mariadb_sql_example_1 -t addons/TechnoLibre_odoo-code-generator-template/code_generator_template_demo_mariadb_sql_example_1 --with_inherit
#./script/addons/install_addons_dev.sh test_template code_generator_template_demo_mariadb_sql_example_1
./script/code_generator/install_and_test_code_generator.sh test_template code_generator_template_demo_mariadb_sql_example_1 ./addons/TechnoLibre_odoo-code-generator-template code_generator_demo_mariadb_sql_example_1
.PHONY: test_code_generator_demo_mariadb_sql_example_1
test_code_generator_demo_mariadb_sql_example_1:
./script/code_generator/check_git_change_code_generator.sh ./addons/TechnoLibre_odoo-code-generator-template
./script/db_restore.py --database test_code_generator
./script/addons/install_addons_dev.sh test_code_generator code_generator_portal
#./script/addons/install_addons_dev.sh test_code_generator code_generator_demo_mariadb_sql_example_1
./script/code_generator/install_and_test_code_generator.sh test_code_generator code_generator_demo_mariadb_sql_example_1 ./addons/TechnoLibre_odoo-code-generator-template demo_mariadb_sql_example_1
##############
# tag #
@ -328,22 +496,39 @@ open_terminal:
# format #
############
.PHONY: format
format: format_code_generator format_code_generator_template format_script
format:
./script/make.sh format_code_generator
./script/make.sh format_code_generator_template
./script/make.sh format_script
.PHONY: format_code_generator
format_code_generator:
.venv/bin/isort --profile black -l 79 ./addons/TechnoLibre_odoo-code-generator/
./script/maintenance/black.sh ./addons/TechnoLibre_odoo-code-generator/
#./script/maintenance/prettier_xml.sh ./addons/TechnoLibre_odoo-code-generator/
.PHONY: format_code_generator_template
format_code_generator_template:
.venv/bin/isort --profile black -l 79 ./addons/TechnoLibre_odoo-code-generator-template/
./script/maintenance/black.sh ./addons/TechnoLibre_odoo-code-generator-template/
#./script/maintenance/prettier_xml.sh ./addons/TechnoLibre_odoo-code-generator-template/
.PHONY: format_script
format_script:
#.venv/bin/isort --profile black -l 79 ./script/ --gitignore
./script/maintenance/black.sh ./script/
.PHONY: format_script_isort_only
format_script_isort_only:
.venv/bin/isort --profile black -l 79 ./script/ --gitignore
#########
# log #
#########
.PHONY: log_show_test
log_show_test:
vim ${LOG_FILE}
###########
# clean #
###########
@ -372,7 +557,9 @@ docker_stop:
docker-compose down
.PHONY: docker_restart_daemon
docker_restart_daemon: docker_stop docker_run_daemon
docker_restart_daemon:
./script/make.sh docker_stop
./script/make.sh docker_run_daemon
.PHONY: docker_show_databases
docker_show_databases:
@ -500,21 +687,41 @@ config_gen_image_db:
i18n_generate_demo_portal:
./.venv/bin/python3 ./odoo/odoo-bin i18n --database code_generator --module demo_portal --addons_path addons/TechnoLibre_odoo-code-generator
###########
# Clean #
###########
.PHONY: clean
clean:
find . -type f -name '*.py[co]' -delete -o -type d -name __pycache__ -delete
###################
# Documentation #
###################
# documentation all
.PHONY: doc
doc: doc_dev doc_migration doc_test doc_user
doc:
./script/make.sh doc_dev
./script/make.sh doc_migration
./script/make.sh doc_test
./script/make.sh doc_user
./script/make.sh doc_markdown
# documentation clean all
.PHONY: doc_clean
doc_clean: doc_clean_dev doc_clean_migration doc_clean_test doc_clean_user
doc_clean:
./script/make.sh doc_clean_dev
./script/make.sh doc_clean_migration
./script/make.sh doc_clean_test
./script/make.sh doc_clean_user
# documentation dev
.PHONY: doc_dev
doc_dev:
source ./.venv/bin/activate && make -C doc/itpp-labs_odoo-development/docs html || exit 1
.PHONY: open_doc_dev
open_doc_dev:
-$(BROWSER) doc/itpp-labs_odoo-development/docs/_build/html/index.html
.PHONY: doc_clean_dev
@ -525,6 +732,9 @@ doc_clean_dev:
.PHONY: doc_migration
doc_migration:
source ./.venv/bin/activate && make -C doc/itpp-labs_odoo-port-docs/docs html || exit 1
.PHONY: open_doc_migration
open_doc_migration:
-$(BROWSER) doc/itpp-labs_odoo-port-docs/docs/_build/html/index.html
.PHONY: doc_clean_migration
@ -535,6 +745,9 @@ doc_clean_migration:
.PHONY: doc_test
doc_test:
source ./.venv/bin/activate && make -C doc/itpp-labs_odoo-test-docs/doc-src html || exit 1
.PHONY: open_doc_test
open_doc_test:
-$(BROWSER) doc/itpp-labs_odoo-test-docs/doc-src/_build/html/index.html
.PHONY: doc_clean_test
@ -545,6 +758,9 @@ doc_clean_test:
.PHONY: doc_user
doc_user:
source ./.venv/bin/activate && make -C doc/odoo_documentation-user html || exit 1
.PHONY: open_doc_user
open_doc_user:
-$(BROWSER) doc/odoo_documentation-user/_build/html/index.html
.PHONY: doc_clean_user

View file

@ -2,6 +2,10 @@
Select a guide to install your environment.
## Easy way to run locally
Into Ubuntu, minimal dependency:
```bash
sudo apt install make git
```
Clone the project:
```bash
git clone https://github.com/ERPLibre/ERPLibre.git

View file

@ -197,6 +197,24 @@ source ./.venv/bin/activate
python odoo/odoo-bin scaffold MODULE_NAME addons/REPO_NAME/
```
## Use Code generator
Read CODE_GENERATOR.md.
# Version
Read GIT_REPO.md to understand how changer version.
## Python version
Your actual version is in file .python-version. Use script `./script/version/change_python_version.sh 3.7.12` to change to version 3.7.12 .
Run the installation, `make install_dev`.
Update poetry, `./script/poetry_update.py`.
Create docker, `make docker_build`.
# Pull request
## Show all pull requests from organization

View file

@ -1,5 +1,19 @@
# FAQ
## Scripting
### Search all duplicate file recursively in given directory
```bash
find . -type f -printf '%p/ %f\n' | sort -k2 | uniq -f1 --all-repeated=separate
```
### Search all duplicate directory recursively in given directory
```bash
find . -type d -printf '%p/ %f\n' | sort -k2 | uniq -f1 --all-repeated=separate
```
## Networking
Show all open port

View file

@ -45,6 +45,7 @@ make format
To generate database images in directory `./image_db`, run:
```bash
make config_gen_all
make image_db_create_all
```
@ -73,6 +74,8 @@ grep --color=always --exclude-dir={.repo,.venv,.git} --exclude="*.svg" -nri v1.2
Replace if need it to new version.
Update file `./pyproject.toml` in [tool.poetry], line `version =`.
### Test production Ubuntu environment
Follow instructions in [PRODUCTION.md](./PRODUCTION.md).
@ -185,6 +188,10 @@ List your docker version
You need to push your docker image and update your tag, like 1.0.1:
> docker push technolibre/erplibre:VERSION
## Do a release on github
Visit `https://github.com/ERPLibre/ERPLibre/releases/new` and create a release named `v#.#.#` and copy information from CHANGELOG.md.
# TIPS
## Compare repo differences with another ERPLibre project

View file

@ -1,4 +1,4 @@
FROM python:3.7.7-slim-buster
FROM python:3.7.12-slim-buster
MAINTAINER TechnoLibre <docker@technolibre.ca>
SHELL ["/bin/bash", "-xo", "pipefail", "-c"]

View file

@ -1 +1 @@
3.7.7
3.7.12

View file

@ -15,3 +15,4 @@ pythonjsonlogger
python-alipay-sdk
pyrfc
MySQLdb
formiodata

View file

@ -13,6 +13,7 @@
<remote name="itpp-labs" fetch="https://github.com/ERPLibre/"/>
<remote name="kinjal-sorathiya" fetch="https://github.com/ERPLibre/"/>
<remote name="muk-it" fetch="https://github.com/ERPLibre/"/>
<remote name="novacode-nl" fetch="https://github.com/ERPLibre/"/>
<remote name="obayit" fetch="https://github.com/ERPLibre/"/>
<remote name="odoo" fetch="https://github.com/ERPLibre/"/>
<remote name="odooaktiv" fetch="https://github.com/ERPLibre/"/>
@ -59,6 +60,7 @@
<project name="ddmrp.git" path="addons/OCA_ddmrp" remote="OCA" groups="addons"/>
<project name="delivery-carrier.git" path="addons/OCA_delivery-carrier" remote="OCA" groups="addons"/>
<project name="deltatech.git" path="addons/dhongu_deltatech" remote="dhongu" groups="addons"/>
<project name="design-themes.git" path="addons/odoo_design-themes" remote="odoo" revision="12.0_dev" groups="addons,code_generator,image_db"/>
<project name="development.git" path="addons/MathBenTech_development" remote="MathBenTech" groups="addons,base"/>
<project name="documentation-user.git" path="doc/odoo_documentation-user" remote="odoo" groups="odoo"/>
<project name="donation.git" path="addons/OCA_donation" remote="OCA" revision="12.0_module_donation_website" groups="addons"/>
@ -85,7 +87,7 @@
<project name="muk_base.git" path="addons/muk-it_muk_base" remote="muk-it" revision="12.0_dev" groups="addons,base"/>
<project name="muk_dms.git" path="addons/muk-it_muk_dms" remote="muk-it" groups="addons"/>
<project name="muk_docs.git" path="addons/muk-it_muk_docs" remote="muk-it" groups="addons"/>
<project name="muk_misc.git" path="addons/muk-it_muk_misc" remote="muk-it" groups="addons,base"/>
<project name="muk_misc.git" path="addons/muk-it_muk_misc" remote="muk-it" revision="12.0_dev" groups="addons,base"/>
<project name="muk_quality.git" path="addons/muk-it_muk_quality" remote="muk-it" groups="addons"/>
<project name="muk_web.git" path="addons/muk-it_muk_web" remote="muk-it" revision="12.0_dev" groups="addons,base"/>
<project name="muk_website.git" path="addons/muk-it_muk_website" remote="muk-it" revision="12.0_remove_autoinstall" groups="addons,base"/>
@ -98,9 +100,10 @@
<project name="odoo-development.git" path="doc/itpp-labs_odoo-development" remote="itpp-labs" revision="12.0_dev" groups="odoo"/>
<project name="odoo-entertainment-addons.git" path="addons/Numigi_odoo-entertainment-addons" remote="Numigi" revision="12.0_dev" groups="addons"/>
<project name="odoo-git-addons.git" path="addons/Numigi_odoo-git-addons" remote="Numigi" revision="12.0_dev" groups="addons"/>
<project name="odoo-formio.git" path="addons/novacode-nl_odoo-formio" remote="novacode-nl" groups="addons"/>
<project name="odoo-hr-addons.git" path="addons/Numigi_odoo-hr-addons" remote="Numigi" groups="addons"/>
<project name="odoo-module-migrator.git" path="script/OCA_odoo-module-migrator" remote="OCA" revision="master" groups="odoo"/>
<project name="odoo-partner-addons.git" path="addons/Numigi_odoo-partner-addons" remote="Numigi" revision="12.0_dev" groups="addons,image_db"/>
<project name="odoo-partner-addons.git" path="addons/Numigi_odoo-partner-addons" remote="Numigi" revision="12.0_dev" groups="addons,base,image_db"/>
<project name="odoo-product-addons.git" path="addons/Numigi_odoo-product-addons" remote="Numigi" revision="12.0_dev" groups="addons"/>
<project name="odoo-port-docs.git" path="doc/itpp-labs_odoo-port-docs" remote="itpp-labs" revision="master" groups="odoo"/>
<project name="odoo-product-configurator.git" path="addons/pledra_odoo-product-configurator" remote="pledra" groups="addons"/>
@ -133,8 +136,8 @@
<project name="saas-addons.git" path="addons/it-projects-llc_saas-addons" remote="it-projects-llc" groups="addons"/>
<project name="sale-reporting.git" path="addons/OCA_sale-reporting" remote="OCA" groups="addons"/>
<project name="sale-workflow.git" path="addons/OCA_sale-workflow" remote="OCA" revision="12.0_modules_sale_order_line" groups="addons"/>
<project name="scrummer.git" path="addons/MathBenTech_scrummer" remote="MathBenTech" revision="12.0_dev" groups="addons"/>
<project name="server-auth.git" path="addons/OCA_server-auth" remote="OCA" groups="addons"/>
<project name="scrummer.git" path="addons/MathBenTech_scrummer" remote="MathBenTech" revision="12.0_dev" groups="addons,base"/>
<project name="server-auth.git" path="addons/OCA_server-auth" remote="OCA" groups="addons,base,image_db"/>
<project name="server-backend.git" path="addons/OCA_server-backend" remote="OCA" groups="addons"/>
<project name="server-brand.git" path="addons/OCA_server-brand" remote="OCA" groups="addons,base"/>
<project name="server-env.git" path="addons/OCA_server-env" remote="OCA" groups="addons"/>

2216
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -2,58 +2,68 @@
requires = [ "poetry>=1.0.0",]
build-backend = "poetry.masonry.api"
[tool.isort]
profile = "black"
py_version = 37
[tool.black]
line-length = 79
target-version = [ "py37",]
[tool.poetry]
name = "ERPLibre"
version = "1.1.0"
version = "1.2.1"
description = "Easy way to configure Odoo community"
license = "AGPL-3.0-or-later"
authors = [ "Mathieu Benoit <mathben@technolibre.ca>",]
[tool.poetry.dependencies]
python = "^3.7.7"
python = "^3.7.12"
Asterisk = "^0.0.8"
Babel = "2.3.4"
Babel = "2.9.1"
BeautifulSoup4 = "^4.10.0"
GitPython = "3.1.12"
Jinja2 = "2.11.3"
Mako = "1.0.4"
MarkupSafe = "0.23"
Pillow = "8.3.2"
Pillow = "9.0.0"
PyJWT = "1.7.1"
PyPDF2 = "1.26.0"
PyYAML = "4.2b4"
SOAPpy = "^0.12.22"
Sphinx = ">=2.4.0"
Voicent-Python = "^1.0"
Werkzeug = "0.15.3"
Werkzeug = "0.11.15"
XlsxWriter = "0.9.3"
agithub = "^2.2.2"
altair = "^4.1.0"
argcomplete = "^1.12.3"
altair = "^4.2.0"
argcomplete = "^2.0.0"
astor = "^0.8.1"
bokeh = "1.1.0"
boto3 = "1.9.102"
cachetools = ">=2.0.1"
cerberus = "^1.3.4"
chardet = "3.0.4"
click = "^8.0.1"
click = "^8.0.3"
cloudflare = "^2.8.15"
code_writer = "^1.1.1"
colorama = "^0.4.4"
cryptography = "3.4.8"
css-html-prettify = "^2.5.5"
cython = "^0.29.24"
cython = "^0.29.26"
ddt = "1.2.0"
decorator = "4.0.10"
docutils = "0.16"
ebaysdk = "2.1.5"
email_validator = "^1.1.3"
emoji = "^1.5.0"
emoji = "^1.6.3"
escpos = "^1.9"
extract-msg = "^0.28.7"
extract_msg = "^0.28.7"
extract-msg = "^0.30.0"
extract_msg = "^0.30.0"
factur-x = "^2.3"
feedparser = "5.2.1"
flake8 = "^3.9.2"
flake8 = "^4.0.1"
formio-data = "^0.3.14"
freezegun = "0.3.11"
geojson = "2.4.1"
gevent = "1.3.4"
@ -63,30 +73,31 @@ html2text = "2016.9.19"
html5print = "^0.1.2"
invoice2data = "^0.3.6"
iscompatible = "^0.1.1"
isort = "^5.10.1"
jira = "2.0.0"
js2py = "^0.71"
keystoneauth1 = "3.14.0"
lasso = "^0.0.5"
libsass = "0.12.3"
lxml = "4.6.3"
lxml = "4.7.1"
matplotlib = ">=2.0.0"
mock = "2.0.0"
mpld3 = "0.3"
mysqlclient = "^2.0.3"
mysqlclient = "^2.1.0"
num2words = "0.5.6"
numpy = "1.21.1"
oauthlib = "2.1.0"
"oca.decorators" = "^0.0.1"
ofxparse = "0.16"
openpyxl = "^3.0.9"
openupgradelib = "^3.1.1"
openupgradelib = "^3.3.1"
pandas = "1.2.0"
paramiko = "^2.7.2"
paramiko = "^2.9.2"
passlib = "1.6.5"
pdf2image = "^1.16.0"
pdfminer = "^20191125"
pexpect = "^4.8.0"
phonenumbers = "^8.12.33"
phonenumbers = "^8.12.41"
plotly = "4.1.0"
premailer = "^3.10.0"
psutil = "5.6.6"
@ -94,15 +105,17 @@ psycopg2 = "2.7.3.1"
py-Asterisk = "^0.5.18"
"py3o.formats" = "^0.3"
"py3o.template" = "^0.10.0"
pycountry = "^20.7.3"
pycountry = "^22.1.10"
pycrypto = "^2.6.1"
pydot = "1.2.3"
pygount = "<1.2.0"
pyjsparser = "^2.7.1"
pyldap = "2.4.28"
pymssql = "^2.2.2"
pymssql = "^2.2.3"
pymysql = "^1.0.2"
pyotp = "^2.6.0"
pyparsing = "2.1.10"
pyproj = "^3.2.1"
pyproj = "3.2.1"
pyserial = "3.1.1"
pysftp = "^0.2.9"
python-chess = "<0.24"
@ -112,7 +125,7 @@ python-git = "^2018.2.1"
python-json-logger = "0.1.5"
python-keystoneclient = "3.22.0"
python-slugify = ">=3.0.2"
python-stdnum = "^1.16"
python-stdnum = "^1.17"
python-swiftclient = "3.9.0"
python-u2flib-server = "^5.0.1"
python-u2flib_server = "^5.0.1"
@ -130,13 +143,13 @@ requests-toolbelt = "0.9.1"
retrying = "^1.3.3"
serial = "^0.0.97"
shapely = "1.6.4.post2"
simplejson = "^3.17.5"
simplejson = "^3.17.6"
slugify = "^0.0.1"
sphinx = ">=1.6.7"
sphinx-intl = "^2.0.1"
sphinx-patchqueue = ">=1.0"
sphinx_rtd_theme = "^1.0.0"
sqlalchemy = "^1.4.25"
sqlalchemy = "^1.4.31"
statsd = "3.2.1"
suds-jurko = "0.6"
toml = "^0.10.2"
@ -149,10 +162,10 @@ vcrpy-unittest = "^0.1.7"
vobject = "0.9.3"
voicent-python = "^1.0"
webcolors = "1.10"
websocket-client = "^1.2.1"
wechatpy = "^1.8.15"
websocket-client = "^1.2.3"
wechatpy = "^1.8.18"
wget = "^3.2"
wheel = "^0.37.0"
wheel = "^0.37.1"
xlrd = "1.0.0"
xlwt = "1.3"
xmlformatter = "^0.2.4"

View file

@ -43,6 +43,7 @@ html5print
css-html-prettify
BeautifulSoup4
git+https://github.com/psf/black.git@21.6b0
isort
# For updating poetry
toml
@ -59,6 +60,9 @@ emoji
# Code generator
mysqlclient
# pyproj >=3.3.0 is not compatible with python 3.7
pyproj==3.2.1
# Force update dependency to fix poetry
numpy==1.21.1
@ -67,8 +71,9 @@ numpy==1.21.1
# error with 5.x (ConstructorError: could not determine a constructor for the tag '!record')
# pyyaml==5.4
Jinja2==2.11.3
lxml==4.6.3
lxml==4.7.1
cryptography==3.4.8
psutil==5.6.6
Pillow==8.3.2
Werkzeug==0.15.3
Pillow==9.0.0
Werkzeug==0.11.15
Babel==2.9.1

View file

@ -0,0 +1,115 @@
#!./.venv/bin/python
import argparse
import configparser
import logging
import os
import sys
from collections import defaultdict
CONFIG_PATH = "./config.conf"
logging.basicConfig(
format=(
"%(asctime)s,%(msecs)d %(levelname)-8s [%(filename)s:%(lineno)d]"
" %(message)s"
),
datefmt="%Y-%m-%d:%H:%M:%S",
level=logging.INFO,
)
_logger = logging.getLogger(__name__)
def get_config():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description="""\
Check if module exist and is not multiple here to manage conflict.
""",
epilog="""\
""",
)
parser.add_argument(
"-m",
"--module",
required=True,
help="Module name to search, a list can be use separate by ,",
)
parser.add_argument(
"--debug",
action="store_true",
help="Enable debug output",
)
args = parser.parse_args()
return args
def main():
config = get_config()
if config.debug:
logging.getLogger().setLevel(logging.DEBUG)
config_parser = configparser.ConfigParser()
config_parser.read(CONFIG_PATH)
if "options" in config_parser:
if "addons_path" in config_parser["options"]:
addons_path = config_parser["options"]["addons_path"]
else:
_logger.error(
"Missing item 'addons_path' in section 'options' in"
f" '{CONFIG_PATH}'"
)
return -1
else:
_logger.error(f"Missing section 'options' in '{CONFIG_PATH}'")
return -1
lst_addons_path = addons_path.split(",")
lst_module = config.module.split(",")
dct_module_exist = defaultdict(list)
dct_module_exist_empty = defaultdict(list)
lst_module_not_exist = []
for module in lst_module:
for path in lst_addons_path:
module_path = os.path.join(path, module)
manifest_file_path = os.path.join(module_path, "__manifest__.py")
if os.path.isdir(module_path):
if os.path.isfile(manifest_file_path):
dct_module_exist[module].append(module_path)
else:
dct_module_exist_empty[module].append(module_path)
if module not in dct_module_exist.keys():
lst_module_not_exist.append(module)
is_good = True
if lst_module_not_exist:
is_good = False
module_list = "'" + "', '".join(lst_module_not_exist) + "'"
_logger.error(
"Missing"
f" module{'s' if len(lst_module_not_exist) > 1 else ''} {module_list}"
)
if dct_module_exist:
for key, lst_value in dct_module_exist.items():
if len(lst_value) != 1:
is_good = False
module_list = "'" + "', '".join(lst_value) + "'"
_logger.error(f"Conflict modules: {module_list}")
for value in lst_value:
print(value)
if dct_module_exist_empty:
for key, lst_value in dct_module_exist_empty.items():
module_list = "'" + "', '".join(lst_value) + "'"
_logger.warning(
"Found this directory, but missing __manifest__.py:"
f" {module_list}"
)
return 0 if is_good else -1
if __name__ == "__main__":
sys.exit(main())

View file

@ -1,5 +1,11 @@
#!/usr/bin/env bash
./run.sh --no-http --stop-after-init -d $1 -i $2 -u $2
./script/addons/check_addons_exist.py -m "$2"
retVal=$?
if [[ $retVal -ne 0 ]]; then
echo "Error install_addons.sh"
exit 1
fi
./run.sh --no-http --stop-after-init -d "$1" -i "$2" -u "$2"
retVal=$?
if [[ $retVal -ne 0 ]]; then
echo "Error install_addons.sh"

View file

@ -1,5 +1,11 @@
#!/usr/bin/env bash
./run.sh --no-http --stop-after-init --dev qweb -d $1 -i $2 -u $2
./script/addons/check_addons_exist.py -m "$2"
retVal=$?
if [[ $retVal -ne 0 ]]; then
echo "Error install_addons.sh"
exit 1
fi
./run.sh --no-http --stop-after-init --dev qweb -d "$1" -i "$2" -u "$2"
retVal=$?
if [[ $retVal -ne 0 ]]; then
echo "Error install_addons_dev.sh"

View file

@ -1,6 +1,12 @@
#!/usr/bin/env bash
./script/addons/uninstall_addons.sh $1 $2
./script/addons/install_addons_dev.sh $1 $2
./script/addons/check_addons_exist.py -m "$2"
retVal=$?
if [[ $retVal -ne 0 ]]; then
echo "Error install_addons.sh"
exit 1
fi
./script/addons/uninstall_addons.sh "$1" "$2"
./script/addons/install_addons_dev.sh "$1" "$2"
retVal=$?
if [[ $retVal -ne 0 ]]; then
echo "Error reinstall_addons.sh"

View file

@ -1,2 +1,8 @@
#!/usr/bin/env bash
./run.sh --no-http --stop-after-init -d $1 --uninstall $2
./script/addons/check_addons_exist.py -m "$2"
retVal=$?
if [[ $retVal -ne 0 ]]; then
echo "Error install_addons.sh"
exit 1
fi
./run.sh --no-http --stop-after-init -d "$1" --uninstall "$2"

View file

@ -73,27 +73,41 @@ On_IPurple='\033[0;105m' # Purple
On_ICyan='\033[0;106m' # Cyan
On_IWhite='\033[0;107m' # White
# TODO support argument to test only specified path
check_git() {
REP=$1
cd ${REP}
cd "${REP}" || exit
output=$(git status --porcelain)
if [ -z "$output" ]; then
echo "PASS - ${REP}"
if [ $# -gt 1 ]; then
output=$(git status --porcelain "$2")
else
echo -e "${Red}FAIL - ${REP}${Color_Off}"
output=$(git status --porcelain)
fi
if [ -z "$output" ]; then
if [ $# -gt 1 ]; then
echo "PASS - ${REP}/${2}"
else
echo "PASS - ${REP}"
fi
else
if [ $# -gt 1 ]; then
echo -e "${Red}FAIL - ${REP}${2}${Color_Off}"
else
echo -e "${Red}FAIL - ${REP}${Color_Off}"
fi
echo -e "${BRed}${output}${Color_Off}"
cd - >/dev/null
cd - >/dev/null || exit
exit 1
fi
cd - >/dev/null
cd - >/dev/null || exit
}
if [ $# -gt 0 ]; then
check_git "$1"
if [ $# -gt 1 ]; then
check_git "$1" "$2"
else
check_git "$1"
fi
else
# check_git "./addons/TechnoLibre_odoo-code-generator"
check_git "./addons/TechnoLibre_odoo-code-generator-template"

View file

@ -0,0 +1,60 @@
#!./.venv/bin/python
import argparse
import logging
import os
import sys
logging.basicConfig(level=logging.DEBUG)
_logger = logging.getLogger(__name__)
# TODO Check if exist, (A) master[template], (B) replicator[code_generator], (C) module
# TODO if force, recreate from C
# TODO if c is code_generator_demo with a different name, execute it.
# TODO if a exist, execute it, and execute b.
# TODO open commit view
def get_config():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description="""\
Get the list of updating module in a working path,
for each module, search where it's suppose to generate new code,
compare if the date change of directory is after the starting date.
""",
epilog="""\
""",
)
parser.add_argument(
"-d",
"--directory",
required=True,
help="Directory of the module.",
)
parser.add_argument(
"-m",
"--module_name",
required=True,
help="Module name to create",
)
parser.add_argument(
"-f",
"--force",
required=True,
help="Force override directory and module.",
)
args = parser.parse_args()
return args
def main():
config = get_config()
if not os.path.exists(config.directory):
_logger.error(f"Path directory {config.directory} not exist.")
return -1
return 0
if __name__ == "__main__":
sys.exit(main())

View file

@ -1,29 +1,47 @@
#!/usr/bin/env bash
# $1 is database name
# $2 is module name
# $2 is module name separate by ,
# $3 is directory path to check
# $4 is generated module name separate by ,
./script/addons/install_addons_dev.sh $1 $2
if (($# < 4)); then
echo "ERROR, need 4 arguments: 1-database name, 2-list of module to install, 3-directory to check difference, 4-list of generated module"
exit 1
fi
INIT_DATETIME=$(date +%s)
./script/addons/install_addons_dev.sh "$1" "$2"
retVal=$?
if [[ $retVal -ne 0 ]]; then
echo "Error ./script/addons/install_addons_dev.sh ${1} ${2}"
exit 1
fi
# Check if the code was updated
./script/code_generator/test_code_generator_update_module.py -m "$4" -d "$3" --datetime "${INIT_DATETIME}"
retVal=$?
if [[ $retVal -ne 0 ]]; then
echo "Error ./script/code_generator/test_code_generator_update_module.py ${4} ${3}"
exit 1
fi
# TODO check output when got warning
./script/repo_revert_git_diff_date_from_code_generator.py
# Remove pot and po diff
cd $3
cd "$3" || exit 1
# git 2.22 and more, else use next command
#BRANCH=$(git branch --show-current)
BRANCH=$(git rev-parse --abbrev-ref HEAD)
#BRANCH=$(git rev-parse --abbrev-ref HEAD)
# Support old version git < 2.23.0
# git restore --source="${BRANCH}" "*.po*"
git checkout -- "*.po*"
cd -
./script/maintenance/black.sh $3
cd - || exit 1
./script/maintenance/black.sh "$3"
echo "TEST ${2}"
./script/code_generator/check_git_change_code_generator.sh $3
./script/code_generator/check_git_change_code_generator.sh "$3"
retVal=$?
if [[ $retVal -ne 0 ]]; then
echo "Error ./script/code_generator/check_git_change_code_generator.sh"

View file

@ -0,0 +1,498 @@
#!./.venv/bin/python
import argparse
import logging
import os
import sys
import uuid
from git import Repo
from git.exc import InvalidGitRepositoryError, NoSuchPathError
CODE_GENERATOR_DIRECTORY = "./addons/TechnoLibre_odoo-code-generator-template/"
CODE_GENERATOR_DEMO_NAME = "code_generator_demo"
KEY_REPLACE_CODE_GENERATOR_DEMO = 'MODULE_NAME = "%s"'
logging.basicConfig(
format=(
"%(asctime)s,%(msecs)d %(levelname)-8s [%(filename)s:%(lineno)d]"
" %(message)s"
),
datefmt="%Y-%m-%d:%H:%M:%S",
level=logging.INFO,
)
_logger = logging.getLogger(__name__)
# TODO Check if exist DONE
# TODO change name into code_generator_demo DONE
# TODO Create code generator empty module with demo DONE
# TODO revert code_generator_demo DONE
# TODO execute create_code_generator_from_existing_module.sh with force option
# TODO open web interface on right database already selected locally with make run
def get_config():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description="""\
Create new project for a single module with code generator suite.
""",
epilog="""\
""",
)
parser.add_argument(
"-d",
"--directory",
required=True,
help="Directory of the module, need to be a git root directory.",
)
parser.add_argument(
"-m",
"--module",
required=True,
help="Module name to create",
)
parser.add_argument(
"--directory_code_generator",
help="The directory of the code_generator to use.",
)
parser.add_argument(
"--code_generator_name",
help="The name of the code_generator to use.",
)
parser.add_argument(
"--directory_template_name",
help="The directory of the template to use.",
)
parser.add_argument(
"--template_name",
help="The name of the template to use.",
)
parser.add_argument(
"-f",
"--force",
action="store_true",
help="Force override directory and module.",
)
parser.add_argument(
"--do_not_update_config",
action="store_true",
help=(
"Ignore updating config file. This is a patch for a bug for"
" duplicate path, but 1 relative and the other is absolute."
),
)
parser.add_argument(
"--keep_bd_alive",
action="store_true",
help="By default, the bd is cleaned after a run.",
)
parser.add_argument(
"--debug",
action="store_true",
help="Enable debug output",
)
args = parser.parse_args()
return args
class ProjectManagement:
def __init__(
self,
module_name,
module_directory,
cg_name="",
cg_directory="",
template_name="",
template_directory="",
force=False,
ignore_config=False,
keep_bd_alive=False,
):
self.force = force
self.ignore_config = ignore_config
self.keep_bd_alive = keep_bd_alive
self.msg_error = ""
self.origin_config_txt = ""
self.has_config_update = False
self.module_directory = module_directory
if not os.path.exists(self.module_directory):
self.msg_error = (
f"Path directory '{self.module_directory}' not exist."
)
_logger.error(self.msg_error)
return
self.cg_directory = cg_directory if cg_directory else module_directory
if not os.path.exists(self.cg_directory):
self.msg_error = (
f"Path cg directory '{self.cg_directory}' not exist."
)
_logger.error(self.msg_error)
return
self.template_directory = (
template_directory if template_directory else module_directory
)
if not os.path.exists(self.template_directory):
self.msg_error = (
f"Path template directory '{self.template_directory}' not"
" exist."
)
_logger.error(self.msg_error)
return
if not module_name:
self.msg_error = "Module name is missing."
_logger.error(self.msg_error)
return
# Get module name
self.module_name = module_name
# Get code_generator name
self.cg_name = self._generate_cg_name(default=cg_name)
# Get template name
self.template_name = self._generate_template_name(
default=template_name
)
def _generate_cg_name(self, default=""):
if default:
return default
return f"code_generator_{self.module_name}"
def _generate_template_name(self, default=""):
if default:
return default
return f"code_generator_template_{self.module_name}"
def search_and_replace_file(self, filepath, lst_search_and_replace):
"""
lst_search_and_replace is a list of tuple, first item is search, second is replace
"""
with open(filepath, "r") as file:
txt = file.read()
for search, replace in lst_search_and_replace:
if search not in txt:
self.msg_error = (
f"Cannot find '{search}' in file '{filepath}'"
)
_logger.error(self.msg_error)
return False
txt = txt.replace(search, replace)
with open(filepath, "w") as file:
file.write(txt)
return True
@staticmethod
def validate_path_ready_to_be_override(name, directory, path=""):
if not path:
path = os.path.join(directory, name)
if not os.path.exists(path):
return True
# Check if in git
try:
git_repo = Repo(directory)
except NoSuchPathError:
_logger.error(f"Directory not existing '{directory}'")
return False
except InvalidGitRepositoryError:
_logger.error(
f"The path '{path}' exist, but no git repo, use force to"
" ignore it."
)
return False
status = git_repo.git.status(name, porcelain=True)
if status:
_logger.error(
f"The directory '{path}' has git difference, use force to"
" ignore it."
)
print(status)
return False
return True
@staticmethod
def restore_git_code_generator_demo(
code_generator_demo_path, relative_path
):
try:
git_repo = Repo(code_generator_demo_path)
except NoSuchPathError:
_logger.error(
f"Directory not existing '{code_generator_demo_path}'"
)
return False
except InvalidGitRepositoryError:
_logger.error(
f"The path '{code_generator_demo_path}' exist, but no git repo"
)
return False
git_repo.git.restore(relative_path)
def generate_module(self):
module_path = os.path.join(self.module_directory, self.module_name)
if not self.force and not self.validate_path_ready_to_be_override(
self.module_name, self.module_directory, path=module_path
):
self.msg_error = f"Cannot generate on module path '{module_path}'"
_logger.error(self.msg_error)
return False
cg_path = os.path.join(self.cg_directory, self.cg_name)
if not self.force and not self.validate_path_ready_to_be_override(
self.cg_name, self.cg_directory, path=cg_path
):
self.msg_error = f"Cannot generate on cg path '{cg_path}'"
_logger.error(self.msg_error)
return False
template_path = os.path.join(
self.template_directory, self.template_name
)
template_hooks_py = os.path.join(template_path, "hooks.py")
if not self.force and not self.validate_path_ready_to_be_override(
self.template_name, self.template_directory, path=template_path
):
self.msg_error = (
f"Cannot generate on template path '{template_path}'"
)
_logger.error(self.msg_error)
return False
# Validate code_generator_demo
code_generator_demo_path = os.path.join(
CODE_GENERATOR_DIRECTORY, CODE_GENERATOR_DEMO_NAME
)
code_generator_demo_hooks_py = os.path.join(
code_generator_demo_path, "hooks.py"
)
code_generator_hooks_path_relative = os.path.join(
CODE_GENERATOR_DEMO_NAME, "hooks.py"
)
if not os.path.exists(code_generator_demo_path):
self.msg_error = (
"code_generator_demo is not accessible"
f" '{code_generator_demo_path}'"
)
_logger.error(self.msg_error)
return False
if not (
self.validate_path_ready_to_be_override(
CODE_GENERATOR_DEMO_NAME, CODE_GENERATOR_DIRECTORY
)
and self.search_and_replace_file(
code_generator_demo_hooks_py,
[
(
KEY_REPLACE_CODE_GENERATOR_DEMO
% CODE_GENERATOR_DEMO_NAME,
KEY_REPLACE_CODE_GENERATOR_DEMO % self.template_name,
),
(
'value["enable_sync_template"] = False',
'value["enable_sync_template"] = True',
),
(
"# path_module_generate ="
" os.path.normpath(os.path.join(os.path.dirname(__file__),"
" '..'))",
f'path_module_generate = "{self.module_directory}"',
),
(
'# "path_sync_code": path_module_generate,',
'"path_sync_code": path_module_generate,',
),
(
'# value["template_module_path_generated_extension"]'
' = "."',
'value["template_module_path_generated_extension"] ='
f' "{self.cg_directory}"',
),
],
)
):
return False
self.update_config()
bd_name_demo = f"new_project_code_generator_demo_{uuid.uuid4()}"[:63]
cmd = f"./script/db_restore.py --database {bd_name_demo}"
_logger.info(cmd)
os.system(cmd)
_logger.info("========= GENERATE code_generator_demo =========")
cmd = (
f"./script/addons/install_addons_dev.sh {bd_name_demo}"
" code_generator_demo"
)
os.system(cmd)
if not self.keep_bd_alive:
cmd = (
"./.venv/bin/python3 ./odoo/odoo-bin db --drop --database"
f" {bd_name_demo}"
)
_logger.info(cmd)
os.system(cmd)
# Revert code_generator_demo
self.restore_git_code_generator_demo(
CODE_GENERATOR_DIRECTORY, code_generator_hooks_path_relative
)
# Validate
if not os.path.exists(template_path):
_logger.error(f"Module template not exists '{template_path}'")
self.revert_config()
return False
else:
_logger.info(f"Module template exists '{template_path}'")
self.search_and_replace_file(
template_hooks_py,
[
(
'value["enable_template_wizard_view"] = False',
'value["enable_template_wizard_view"] = True',
),
],
)
# Execute all
bd_name_template = (
f"new_project_code_generator_template_{uuid.uuid4()}"[:63]
)[:63]
cmd = f"./script/db_restore.py --database {bd_name_template}"
os.system(cmd)
_logger.info(cmd)
_logger.info(f"========= GENERATE {self.template_name} =========")
# TODO maybe the module exist somewhere else
if os.path.exists(module_path):
# Install module before running code generator
cmd = (
"./script/code_generator/search_class_model.py --quiet -d"
f" {module_path} -t {template_path}"
)
_logger.info(cmd)
os.system(cmd)
cmd = (
f"./script/addons/install_addons_dev.sh {bd_name_template}"
f" {self.module_name}"
)
_logger.info(cmd)
os.system(cmd)
cmd = (
f"./script/addons/install_addons_dev.sh {bd_name_template}"
f" {self.template_name}"
)
_logger.info(cmd)
os.system(cmd)
if not self.keep_bd_alive:
cmd = (
"./.venv/bin/python3 ./odoo/odoo-bin db --drop --database"
f" {bd_name_template}"
)
_logger.info(cmd)
os.system(cmd)
# Validate
if not os.path.exists(cg_path):
_logger.error(f"Module cg not exists '{cg_path}'")
self.revert_config()
return False
else:
_logger.info(f"Module cg exists '{cg_path}'")
bd_name_generator = f"new_project_code_generator_{uuid.uuid4()}"[:63]
cmd = f"./script/db_restore.py --database {bd_name_generator}"
_logger.info(cmd)
os.system(cmd)
_logger.info(f"========= GENERATE {self.cg_name} =========")
cmd = (
f"./script/addons/install_addons_dev.sh {bd_name_generator}"
f" {self.cg_name}"
)
_logger.info(cmd)
os.system(cmd)
if not self.keep_bd_alive:
cmd = (
"./.venv/bin/python3 ./odoo/odoo-bin db --drop --database"
f" {bd_name_generator}"
)[:63]
_logger.info(cmd)
os.system(cmd)
# Validate
if not os.path.exists(template_path):
_logger.error(f"Module not exists '{module_path}'")
self.revert_config()
return False
else:
_logger.info(f"Module exists '{module_path}'")
self.revert_config()
return True
def update_config(self):
if self.ignore_config:
return
# Backup config and restore it after, check if path exist or add it temporary
with open("./config.conf") as config:
config_txt = config.read()
self.origin_config_txt = config_txt
lst_directory = list(
{
self.cg_directory,
self.module_directory,
self.template_directory,
}
)
lst_directory_to_add = []
for directory in lst_directory:
if directory not in config_txt:
self.has_config_update = True
lst_directory_to_add.append(directory)
if lst_directory_to_add:
new_str = "addons_path = " + ",".join(lst_directory_to_add) + ","
config_txt = config_txt.replace("addons_path = ", new_str)
with open("./config.conf", "w") as config:
config.write(config_txt)
def revert_config(self):
if self.ignore_config:
return
with open("./config.conf", "w") as config:
config.write(self.origin_config_txt)
def main():
config = get_config()
if config.debug:
logging.getLogger().setLevel(logging.DEBUG)
project = ProjectManagement(
config.module,
config.directory,
cg_name=config.code_generator_name,
template_name=config.template_name,
force=config.force,
ignore_config=config.do_not_update_config,
keep_bd_alive=config.keep_bd_alive,
)
if project.msg_error:
return -1
if not project.generate_module():
return -1
return 0
if __name__ == "__main__":
sys.exit(main())

View file

@ -0,0 +1,223 @@
#!./.venv/bin/python
import argparse
# import glob
import ast
import logging
import os
import sys
from pathlib import Path
logging.basicConfig(level=logging.DEBUG)
_logger = logging.getLogger(__name__)
def get_config():
"""Parse command line arguments, extracting the config file name,
returning the union of config file and command line arguments
:return: dict of config file settings and command line arguments
"""
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description="""\
Search all method class and give a list separate by ;
""",
epilog="""\
""",
)
parser.add_argument(
"-d",
"--directory",
dest="directory",
required=True,
help="Directory to execute search in recursive.",
)
parser.add_argument(
"-t",
"--template_dir",
dest="template_dir",
help=(
"Overwrite value template_model_name in template module, give only"
" template source directory, will update file hooks.py"
),
)
parser.add_argument(
"--with_inherit",
action="store_true",
help="Will search inherit model",
)
parser.add_argument(
"-q",
"--quiet",
action="store_true",
help="Don't show output of found model.",
)
args = parser.parse_args()
return args
def search_and_replace(
f_lines, hooks_file_path, models_name, search_word="template_model_name"
):
if not models_name:
return f_lines
t_index = f_lines.find(search_word)
if t_index == -1:
_logger.error(f"Cannot find {search_word} in file {hooks_file_path}")
return -1
t_index_equation = f_lines.index("=", t_index + 1)
if t_index_equation == -1:
_logger.error(f"Cannot find {search_word} = in file {hooks_file_path}")
return -1
# find next character
i = 1
while f_lines[t_index_equation + i] in (" ", "\n"):
i += 1
first_char = f_lines[t_index_equation + i]
if first_char == "(":
second_char = ")"
elif f_lines[t_index_equation + i : t_index_equation + i + 3] == '"""':
first_char = '"""'
second_char = '"""'
else:
second_char = first_char
# t_index_first_quote = f_lines.index(first_char, t_index + 1)
t_index_second_quote = f_lines.index(first_char, t_index_equation + i)
if t_index_second_quote == -1:
_logger.error(
f'Cannot find {search_word} = "##" in file {hooks_file_path}'
)
return -1
t_index_third_quote = f_lines.index(second_char, t_index_second_quote + 1)
if t_index_third_quote == -1:
_logger.error(f"Cannot find third quote in file {hooks_file_path}")
return -1
# if "\n" in models_name:
# new_file_content = (
# f'{f_lines[:t_index_second_quote]}"""{models_name}"""{f_lines[t_index_third_quote + len(second_char):]}'
# )
# else:
# new_file_content = (
# f'{f_lines[:t_index_second_quote]}"{models_name}"{f_lines[t_index_third_quote + len(second_char):]}'
# )
new_file_content = (
f'{f_lines[:t_index_second_quote]}"{models_name}"{f_lines[t_index_third_quote + len(second_char):]}'
)
return new_file_content
def main():
config = get_config()
if not os.path.exists(config.directory):
_logger.error(f"Path directory {config.directory} not exist.")
return -1
lst_model_name = []
lst_model_inherit_name = []
lst_search_target = ("_name",)
lst_search_inherit_target = ("_inherit",) if config.with_inherit else []
# lst_py_file = glob.glob(os.path.join(config.directory, "***", "*.py"))
lst_py_file = Path(config.directory).rglob("*.py")
for py_file in lst_py_file:
if py_file == "__init__.py":
continue
with open(py_file, "r") as source:
f_lines = source.read()
try:
f_ast = ast.parse(f_lines)
except Exception as e:
_logger.error(f"Cannot parse file {py_file}")
continue
for children in f_ast.body:
if type(children) == ast.ClassDef:
# Detect good _name
for node in children.body:
if (
type(node) is ast.Assign
and node.targets
and type(node.targets[0]) is ast.Name
# and node.targets[0].id in ("_name",)
and type(node.value) is ast.Str
):
if (
lst_search_target
and node.targets[0].id in lst_search_target
):
if node.value.s in lst_model_name:
_logger.warning(
"Duplicated model name"
f" {node.value.s} from file {py_file}"
)
else:
lst_model_name.append(node.value.s)
if (
lst_search_inherit_target
and node.targets[0].id
in lst_search_inherit_target
):
if node.value.s in lst_model_inherit_name:
_logger.warning(
"Duplicated model inherit name"
f" {node.value.s} from file {py_file}"
)
else:
lst_model_inherit_name.append(node.value.s)
lst_model_name.sort()
lst_model_inherit_name.sort()
models_name = "; ".join(lst_model_name)
# TODO temporary fix, remove this when it's supported
lst_ignored_inherit = ["portal.mixin", "mail.thread"]
for ignored_inherit in lst_ignored_inherit:
if ignored_inherit in lst_model_inherit_name:
lst_model_inherit_name.remove(ignored_inherit)
models_inherit_name = "; ".join(lst_model_inherit_name)
if not models_name:
_logger.warning(f"Missing models class in {config.directory}")
elif not config.quiet:
# _logger.info(models_name)
print(models_name)
print(models_inherit_name)
if config.template_dir:
if not os.path.exists(config.template_dir):
_logger.error(
f"Path template dir {config.template_dir} not exist."
)
return -1
hooks_file_path = os.path.join(config.template_dir, "hooks.py")
if not os.path.exists(hooks_file_path):
_logger.error(
f"Path template hooks.py file {hooks_file_path} not exist."
)
return -1
with open(hooks_file_path, "r") as source:
f_lines = source.read()
# Throw exception if not found
new_file_content = search_and_replace(
f_lines, hooks_file_path, models_name
)
if models_inherit_name:
new_file_content = search_and_replace(
new_file_content,
hooks_file_path,
models_inherit_name,
search_word="template_inherit_model_name",
)
with open(hooks_file_path, "w") as source:
source.write(new_file_content)
# Call black
os.system(f"./script/maintenance/black.sh {hooks_file_path}")
return 0
if __name__ == "__main__":
status = main()
sys.exit(status)

View file

@ -0,0 +1,89 @@
#!./.venv/bin/python
import argparse
import logging
import os
import sys
logging.basicConfig(level=logging.DEBUG)
_logger = logging.getLogger(__name__)
def get_config():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description="""\
Get the list of updating module in a working path,
for each module, search where it's suppose to generate new code,
compare if the date change of directory is after the starting date.
""",
epilog="""\
""",
)
parser.add_argument(
"-d",
"--directory",
dest="directory",
required=True,
help="Directory of the module to check.",
)
parser.add_argument(
"-m",
"--module_list",
dest="module_list",
required=True,
help="List of module, separate by ','",
)
parser.add_argument(
"--datetime",
dest="datetime",
required=True,
help="The datetime to check if the generated module is after.",
)
args = parser.parse_args()
return args
def main():
config = get_config()
if not os.path.exists(config.directory):
_logger.error(f"Path directory {config.directory} not exist.")
return -1
lst_module = [a for a in config.module_list.split(",") if a.split()]
if not lst_module:
_logger.error(f"No module was selected, be sure to use --module_list")
return -1
lst_result_good = []
lst_result_wrong = []
for module_name in lst_module:
if config.directory.endswith(module_name):
module_path = config.directory
else:
module_path = os.path.join(config.directory, module_name)
if not os.path.exists(module_path):
_logger.error(
f"Module '{module_name}' not existing in path"
f" '{config.directory}'."
)
return -1
stat = os.stat(module_path)
result = stat.st_mtime > float(config.datetime)
if result:
lst_result_good.append(module_name)
else:
lst_result_wrong.append(module_name)
if lst_result_wrong:
_logger.error(
"FAIL - Some modules wasn't updated, did you execute the code"
f" generator? {lst_result_wrong}"
)
return -1
elif lst_result_good:
_logger.info("SUCCESS - All modules are updated.")
return 0
if __name__ == "__main__":
sys.exit(main())

View file

@ -1,15 +1,16 @@
#!./.venv/bin/python
import os
import sys
import argparse
import logging
import os
import subprocess
import sys
from code_writer import CodeWriter
# import tokenize
from script.git_tool import GitTool
# import tokenize
def get_config():
"""Parse command line arguments, extracting the config file name,

View file

@ -1,10 +1,11 @@
#!./.venv/bin/python
import os
import sys
import argparse
import logging
import os
import sys
from xml.dom import Node, minidom
from code_writer import CodeWriter
from xml.dom import minidom, Node
from script.git_tool import GitTool

View file

@ -1,9 +1,9 @@
#!./.venv/bin/python
import argparse
import csv
import logging
import os
import sys
import argparse
import logging
import csv
new_path = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))
sys.path.append(new_path)

14
script/database/README.md Normal file
View file

@ -0,0 +1,14 @@
# Database
This section is for code generator database migrator.
This configuration is for development environnement.
You need to install script `./script/install_dev_extra_ubuntu.sh`.
## Restore database
Run script to restore database:
```bash
./script/database/restore_mariadb_sql_example_1.sh
```

44
script/database/db_drop_all.py Executable file
View file

@ -0,0 +1,44 @@
#!./.venv/bin/python
import argparse
import logging
import subprocess
import sys
logging.basicConfig(level=logging.DEBUG)
_logger = logging.getLogger(__name__)
def execute_shell(cmd):
out = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
return out.decode().strip() if out else ""
def get_config():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description="""\
Drop all database, caution!
""",
epilog="""\
""",
)
args = parser.parse_args()
return args
def main():
config = get_config()
out_db = execute_shell("./.venv/bin/python3 ./odoo/odoo-bin db --list")
lst_db = out_db.split("\n")
for db_name in lst_db:
execute_shell(
"./.venv/bin/python3 ./odoo/odoo-bin db --drop --database"
f" {db_name}"
)
print(f"{db_name} deleted")
return 0
if __name__ == "__main__":
sys.exit(main())

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,29 @@
#!/usr/bin/env bash
SQL_PATH=./script/database/mariadb_sql_example_1.sql
# You need to set no password to mysql root user
# SET PASSWORD FOR root@localhost='';
# FLUSH PRIVILEGES;
# Second solution
# ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '';
# FLUSH PRIVILEGES;
echo "Create database and user"
mysql -u root << EOF
DROP DATABASE IF EXISTS mariadb_sql_example_1;
CREATE USER IF NOT EXISTS 'organization'@'localhost' IDENTIFIED BY 'organization';
GRANT ALL PRIVILEGES ON *.* TO 'organization'@'localhost' IDENTIFIED BY 'organization';
FLUSH PRIVILEGES;
CREATE DATABASE mariadb_sql_example_1;
EOF
echo "Fix SQL file"
sed -i "s/'0000-00-00'/NULL/g" ${SQL_PATH}
echo "Import SQL file"
mysql -u organization -porganization mariadb_sql_example_1 < ${SQL_PATH}
echo "Fix SQL in database"
./.venv/bin/python ./script/database/fix_mariadb_sql_example_1.py

View file

@ -1,10 +1,10 @@
#!./.venv/bin/python
import os
import sys
import argparse
import logging
import configparser
import getpass
import logging
import os
import sys
from subprocess import check_output
new_path = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))

View file

@ -1,6 +1,7 @@
#!./.venv/bin/python
import argparse
import logging
import CloudFlare
import requests

View file

@ -1,8 +1,9 @@
#!./.venv/bin/python
import os
import sys
import argparse
import logging
import os
import sys
import yaml
new_path = os.path.normpath(

View file

@ -1,12 +1,14 @@
from __future__ import print_function
import argparse
import os.path
import shutil
import yaml # pip install PyYAML
from agithub.GitHub import GitHub # pip install agithub
from git import Repo # pip install gitpython
from giturlparse import parse # pip install giturlparse
from retrying import retry # pip install retrying
import yaml # pip install PyYAML
DEFAULT_CONFIG_FILENAME = "~/.github/fork_github_repo.yaml"

View file

@ -1,8 +1,9 @@
#!./.venv/bin/python
import os
import sys
import argparse
import logging
import os
import sys
from git import Repo
from retrying import retry # pip install retrying

View file

@ -1,10 +1,11 @@
#!./.venv/bin/python
import os
import sys
import argparse
import logging
from git import Repo
import os
import sys
import git
from git import Repo
new_path = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))
sys.path.append(new_path)

View file

@ -142,7 +142,9 @@ if [[ ${EL_MINIMAL_ADDONS} = "False" ]]; then
printf "${EL_HOME}/addons/muk-it_muk_quality," >> ${EL_CONFIG_FILE}
printf "${EL_HOME}/addons/muk-it_muk_web," >> ${EL_CONFIG_FILE}
printf "${EL_HOME}/addons/muk-it_muk_website," >> ${EL_CONFIG_FILE}
printf "${EL_HOME}/addons/novacode-nl_odoo-formio," >> ${EL_CONFIG_FILE}
printf "${EL_HOME}/addons/obayit_odoo_dhtmlxgantt," >> ${EL_CONFIG_FILE}
printf "${EL_HOME}/addons/odoo_design-themes," >> ${EL_CONFIG_FILE}
printf "${EL_HOME}/addons/odooaktiv_QuotationRevision," >> ${EL_CONFIG_FILE}
printf "${EL_HOME}/addons/odooaktiv_product_rating_app," >> ${EL_CONFIG_FILE}
printf "${EL_HOME}/addons/odoomates_odooapps," >> ${EL_CONFIG_FILE}

View file

@ -0,0 +1,104 @@
#!./.venv/bin/python
# © 2021 TechnoLibre (http://www.technolibre.ca)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import argparse
import logging
import os
import shutil
import subprocess
import tempfile
from git import Repo
_logger = logging.getLogger(__name__)
def get_config():
"""Parse command line arguments, extracting the config file name,
returning the union of config file and command line arguments
:return: dict of config file settings and command line arguments
"""
# TODO update description
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description="""Copy a directory in a temporary directory to compare with a generated code to understand the difference.""",
epilog="""\
""",
)
parser.add_argument(
"--directory1",
required=True,
help="Compare input1 to input2. Input1 is older config.",
)
parser.add_argument(
"--directory2",
required=True,
help="The generated code directory",
)
parser.add_argument(
"--replace_directory",
action="store_true",
help="Erase after first commit to see removing file.",
)
parser.add_argument(
"-q",
"--quiet",
action="store_true",
help="Don't show output of difference.",
)
parser.add_argument("--git_gui", action="store_true", help="Open git gui.")
parser.add_argument("--meld", action="store_true", help="Open meld.")
parser.add_argument(
"--clear",
action="store_true",
help="Delete temporary directory at the end of execution.",
)
args = parser.parse_args()
return args
def main():
config = get_config()
# path = tempfile.mkdtemp()
path = tempfile.NamedTemporaryFile().name
if os.path.exists(config.directory1) and os.path.exists(config.directory2):
if config.git_gui:
shutil.copytree(config.directory1, path)
shutil.copy2("./.gitignore", path)
# repo = Repo(path)
repo = Repo.init(path=path)
repo.git.add(".")
repo.git.commit("-m", "First commit")
# shutil.copy2(config.directory2, path)
if config.replace_directory:
subprocess.call(f"rm -r {path}/*", shell=True)
subprocess.call(f"cp -r {config.directory2}/* {path}", shell=True)
status = repo.git.diff()
if not config.quiet:
print(status)
try:
subprocess.call(f"cd {path};git gui", shell=True)
except:
pass
if config.clear:
shutil.rmtree(path, ignore_errors=True)
elif config.meld:
try:
subprocess.call(f"make clean", shell=True)
subprocess.call(
f"meld {config.directory1} {config.directory2}", shell=True
)
except:
pass
elif not os.path.exists(config.directory1):
_logger.error(f"Path is not existing {config.directory1}")
# elif not os.path.exists(config.directory2):
else:
_logger.error(f"Path is not existing {config.directory2}")
if __name__ == "__main__":
main()

View file

@ -1,10 +1,10 @@
#!./.venv/bin/python
import os
import sys
import argparse
import logging
from git import Repo
import os
import sys
from git import Repo
from retrying import retry # pip install retrying
new_path = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))

View file

@ -1,8 +1,9 @@
#!./.venv/bin/python
import os
import sys
import argparse
import logging
import os
import sys
from git import Repo
new_path = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))

View file

@ -1,9 +1,9 @@
#!./.venv/bin/python
import argparse
import copy
import logging
import os
import sys
import argparse
import logging
import copy
new_path = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))
sys.path.append(new_path)

View file

@ -1,8 +1,8 @@
#!./.venv/bin/python
import os
import sys
import argparse
import logging
import os
import sys
new_path = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))
sys.path.append(new_path)

View file

@ -1,10 +1,11 @@
#!./.venv/bin/python
import os
import sys
import argparse
import logging
from git import Repo
import os
import sys
import git
from git import Repo
new_path = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))
sys.path.append(new_path)

View file

@ -1,13 +1,13 @@
#!./.venv/bin/python
import os
import sys
import argparse
import logging
import os
import sys
from collections import defaultdict
from colorama import Fore, Style
from git import Repo
from git.exc import GitCommandError, NoSuchPathError
from colorama import Fore
from colorama import Style
from collections import defaultdict
new_path = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))
sys.path.append(new_path)

View file

@ -3,16 +3,16 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import os
import webbrowser
from retrying import retry # pip install retrying
from agithub.GitHub import GitHub # pip install agithub
from giturlparse import parse # pip install giturlparse
import xmltodict
from collections import OrderedDict
from git import Repo
import git
from typing import List
import git
import xmltodict
from agithub.GitHub import GitHub # pip install agithub
from git import Repo
from giturlparse import parse # pip install giturlparse
from retrying import retry # pip install retrying
CST_FILE_SOURCE_REPO_ADDONS = "source_repo_addons.csv"
CST_EL_GITHUB_TOKEN = "EL_GITHUB_TOKEN"
DEFAULT_PROJECT_NAME = "ERPLibre"
@ -391,11 +391,7 @@ class GitTool:
lst_result = []
for repo in lst_repo:
# Exception, ignore addons/OCA_web and root
if (
"addons/OCA_web" == repo.get("path")
or "odoo" == repo.get("path")
or "image_db" == repo.get("path")
):
if repo.get("path") in ["addons/OCA_web", "odoo", "image_db"]:
continue
str_repo = (
f' printf "${{EL_HOME}}/{repo.get("path")}," >> '

View file

@ -1,8 +1,9 @@
#!./.venv/bin/python
import os
import sys
import argparse
import logging
import os
import sys
from git import Repo # pip install gitpython
from retrying import retry # pip install retrying

View file

@ -37,8 +37,8 @@ sudo npm install -g rtlcss
sudo npm install -g less
sudo npm install -g prettier
sudo npm install -g prettier @prettier/plugin-xml
yes n|pyenv install 3.7.7
pyenv local 3.7.7
yes n|pyenv install 3.7.12
pyenv local 3.7.12
echo 'export PATH="/usr/local/opt/openssl@1.1/bin:$PATH"' >> ~/.zshrc
@ -49,8 +49,8 @@ curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poet
# Install Wkhtmltopdf if needed
#--------------------------------------------------
echo "\n---- Installing Wkhtmltopdf if needed ----"
if [ ! -f "wkhtmltox-0.12.6-1.macos-cocoa.pkg" ]; then
sudo wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox-0.12.6-1.macos-cocoa.pkg
sudo sudo installer -pkg wkhtmltox-0.12.6-1.macos-cocoa.pkg -target /
if [ ! -f "wkhtmltox-0.12.6-2.macos-cocoa.pkg" ]; then
sudo wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-2/wkhtmltox-0.12.6-2.macos-cocoa.pkg
sudo sudo installer -pkg wkhtmltox-0.12.6-2.macos-cocoa.pkg -target /
else echo "Wkhtmltopdf already installed"
fi

View file

@ -53,7 +53,9 @@ sudo apt-get install libmariadbd-dev -y
sudo apt-get install make libssl-dev zlib1g-dev libreadline-dev libsqlite3-dev curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev liblzma-dev -y
echo -e "\n---- Installing nodeJS NPM and rtlcss for LTR support ----"
sudo apt-get install nodejs npm -y
curl -fsSL https://deb.nodesource.com/setup_current.x | sudo -E bash -
sudo apt-get install -y nodejs
sudo npm install npm@latest -g
sudo npm install -g rtlcss
sudo npm install -g less

View file

@ -1,16 +1,17 @@
#!/usr/bin/env bash
################################################################################
# Script for installing ERPLibre locally for dev
# Author: Alexandre Ferreira Benevides
################################################################################
if [[ "${OSTYPE}" == "linux-gnu" ]]; then
OS=$(lsb_release -si)
VERSION=$(cat /etc/issue)
if [[ "${OS}" == "Ubuntu" ]]; then
echo "\n---- linux-gnu installation process started ----"
./script/install_debian_dependency.sh
if [[ "${VERSION}" == Ubuntu\ 18.04* || "${VERSION}" == Ubuntu\ 20.04* ]]; then
echo "\n---- linux-gnu installation process started ----"
./script/install_debian_dependency.sh
else
echo "Your version is not supported, only support 18.04 and 20.04 : ${VERSION}"
fi
else
echo "Your Linux system is not supported."
echo "Your Linux system is not supported, only support Ubuntu 18.04 or Ubuntu 20.04."
fi
elif [[ "${OSTYPE}" == "darwin"* ]]; then
echo "\n---- Darwin installation process started ----"

View file

@ -0,0 +1,40 @@
#!/usr/bin/env bash
# Need this for test extra
if [[ "${OSTYPE}" == "linux-gnu" ]]; then
OS=$(lsb_release -si)
VERSION=$(cat /etc/issue)
if [[ "${OS}" == "Ubuntu" ]]; then
if [[ "${VERSION}" == Ubuntu\ 18.04* || "${VERSION}" == Ubuntu\ 20.04* ]]; then
# Install mariadb
sudo apt install mariadb-client mariadb-server
echo "This is not for production, this is for development. Mysql user root will be accessible without password."
sudo mysql -u root << EOF
SET PASSWORD FOR root@localhost='';
FLUSH PRIVILEGES;
EOF
# Install docker
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
# Run without root
#sudo groupadd docker
sudo usermod -aG docker "$USER"
#newgrp docker
# Install docker-compose
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
else
echo "Your version is not supported, only support 18.04 and 20.04 : ${VERSION}"
fi
else
echo "Your Linux system is not supported, only support Ubuntu 18.04 or Ubuntu 20.04."
fi
fi

View file

@ -25,7 +25,7 @@ if [[ ! -d "./addons/addons" ]]; then
fi
PYENV_PATH=~/.pyenv
PYTHON_VERSION=3.7.7
PYTHON_VERSION=3.7.12
PYENV_VERSION_PATH=${PYENV_PATH}/versions/${PYTHON_VERSION}
PYTHON_EXEC=${PYENV_VERSION_PATH}/bin/python
POETRY_PATH=~/.poetry

View file

@ -1,4 +1,15 @@
#!/usr/bin/env bash
echo "==$&%== Begin ${@}"
echo "
===> ${@}
"
time make $@
echo "==$&%== End ${@}"
retVal=$?
echo "
<=== ${@}
"
if [[ $retVal -ne 0 ]]; then
echo "Error make ${@}"
exit 1
fi

View file

@ -1,12 +1,12 @@
#!./.venv/bin/python
import argparse
import json
import logging
import os
import sys
import argparse
import logging
import zipfile
import json
from colorama import Fore
from colorama import Style
from colorama import Fore, Style
new_path = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))
sys.path.append(new_path)

View file

@ -5,6 +5,7 @@ paths=(
"${working_path}/"
"${working_path}/addons/TechnoLibre_odoo-code-generator"
"${working_path}/addons/TechnoLibre_odoo-code-generator-template"
"${working_path}/addons/OCA_server-tools"
)
cmd_before="cd "
@ -13,7 +14,7 @@ cmd_after=";gnome-terminal --tab -- bash -c 'git status;bash';"
#cmd_after=";gnome-terminal --tab;"
LONGCMD=""
for t in ${paths[@]}; do
for t in "${paths[@]}"; do
LONGCMD+=${cmd_before}${t}${cmd_after}
done

View file

@ -1,13 +1,14 @@
#!./.venv/bin/python
import argparse
import ast
import logging
import os
import sys
import argparse
import logging
import toml
import ast
from collections import OrderedDict, defaultdict
from pathlib import Path
import iscompatible
import toml
new_path = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))
sys.path.append(new_path)

View file

@ -1,8 +1,8 @@
#!./.venv/bin/python
import os
import sys
import argparse
import logging
import os
import sys
new_path = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))
sys.path.append(new_path)

View file

@ -1,9 +1,10 @@
#!./.venv/bin/python
import os
import sys
import argparse
import logging
import os
import sys
from pathlib import Path
from git import Repo # pip install gitpython
from git.exc import GitCommandError

View file

@ -1,15 +1,20 @@
#!./.venv/bin/python
import os
import sys
import argparse
import logging
import os
import re
import sys
import git
from unidiff import PatchSet
import re
new_path = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))
sys.path.append(new_path)
logging.basicConfig(
format="%(asctime)s %(levelname)s: %(message)s",
datefmt="%Y-%m-%d %I:%M:%S",
)
_logger = logging.getLogger(__name__)
@ -62,6 +67,7 @@ def main():
with open(file_real_path, "r") as file:
lst_data = file.readlines()
for data in lst_data:
# TODO this remove code begin with this string, why do we remove it?
if data.startswith("#: code:addons/addons/"):
is_modified = True
else:

View file

@ -1,12 +1,12 @@
#!./.venv/bin/python
import os
import sys
import argparse
import logging
import os
import sys
from colorama import Fore, Style
from git import Repo # pip install gitpython
from retrying import retry # pip install retrying
from colorama import Fore
from colorama import Style
new_path = os.path.normpath(os.path.join(os.path.dirname(__file__), ".."))
sys.path.append(new_path)

View file

@ -0,0 +1,77 @@
#!/usr/bin/env bash
if (($# < 1)); then
echo "ERROR, need 1 arguments: log file path"
exit 1
fi
Color_Off='\033[0m'
Red='\033[0;31m'
Blue='\033[0;34m'
Yellow='\033[0;33m'
LOG_FILE="${1}"
echo "== RESULT from ${LOG_FILE} =="
WARNING_MESSAGE=$(grep -i warning "${LOG_FILE}")
WARNING_MESSAGE=$(echo "${WARNING_MESSAGE}"|grep -v "have the same label:")
WARNING_MESSAGE=$(echo "${WARNING_MESSAGE}"|grep -v "odoo.addons.code_generator.extractor_module_file: Ignore next error about ALTER TABLE DROP CONSTRAINT.")
# Remove empty line
if [[ -z "${WARNING_MESSAGE// }" ]]; then
COUNT_WARNING=0
else
COUNT_WARNING=$(echo "${WARNING_MESSAGE}"|wc -l)
fi
ERROR_MESSAGE=$(grep -i error "${LOG_FILE}")
ERROR_MESSAGE=$(echo "${ERROR_MESSAGE}"|grep -v "fetchmail_notify_error_to_sender")
ERROR_MESSAGE=$(echo "${ERROR_MESSAGE}"|grep -v "odoo.sql_db: bad query: ALTER TABLE \"db_backup\" DROP CONSTRAINT \"db_backup_db_backup_name_unique\"")
ERROR_MESSAGE=$(echo "${ERROR_MESSAGE}"|grep -v "ERROR: constraint \"db_backup_db_backup_name_unique\" of relation \"db_backup\" does not exist")
ERROR_MESSAGE=$(echo "${ERROR_MESSAGE}"|grep -v "odoo.sql_db: bad query: ALTER TABLE \"db_backup\" DROP CONSTRAINT \"db_backup_db_backup_days_to_keep_positive\"")
ERROR_MESSAGE=$(echo "${ERROR_MESSAGE}"|grep -v "ERROR: constraint \"db_backup_db_backup_days_to_keep_positive\" of relation \"db_backup\" does not exist")
ERROR_MESSAGE=$(echo "${ERROR_MESSAGE}"|grep -v "odoo.addons.code_generator.extractor_module_file: Ignore next error about ALTER TABLE DROP CONSTRAINT.")
# Remove empty line
if [[ -z "${ERROR_MESSAGE// }" ]]; then
COUNT_ERROR=0
else
COUNT_ERROR=$(echo "${ERROR_MESSAGE}"|wc -l)
fi
echo_count_warnings () {
if (("${COUNT_WARNING}" > 1)); then
echo -e "${Yellow}${COUNT_WARNING} WARNINGS${Color_Off}"
else
echo -e "${Yellow}${COUNT_WARNING} WARNING${Color_Off}"
fi
}
echo_count_errors () {
if (("${COUNT_ERROR}" > 1)); then
echo -e "${Red}${COUNT_ERROR} ERRORS${Color_Off}"
else
echo -e "${Red}${COUNT_ERROR} ERROR${Color_Off}"
fi
}
echo -e "${Blue}Summary of check result${Color_Off}"
if (("${COUNT_WARNING}" > 0)); then
echo_count_warnings
fi
if (("${COUNT_ERROR}" > 0)); then
echo_count_errors
fi
echo -e "${Blue}Log result${Color_Off}"
if (("${COUNT_WARNING}" > 0)); then
if (("${COUNT_ERROR}" > 0)); then
echo_count_warnings
fi
echo -e "${WARNING_MESSAGE}"
fi
if (("${COUNT_ERROR}" > 0)); then
if (("${COUNT_WARNING}" > 0)); then
echo_count_errors
fi
echo -e "${ERROR_MESSAGE}"
fi
echo -e "${Blue}End of check result${Color_Off}"

607
script/test/run_parallel_test.py Executable file
View file

@ -0,0 +1,607 @@
#!./.venv/bin/python
import argparse
import asyncio
import datetime
import logging
import os
import sys
import time
import uuid
from typing import Tuple
from colorama import Fore
logging.basicConfig(level=logging.DEBUG)
_logger = logging.getLogger(__name__)
LOG_FILE = "./.venv/make_test.log"
def get_config():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description="""\
Run code generator test in parallel.
""",
epilog="""\
""",
)
parser.add_argument(
"--ignore_init_check_git",
action="store_true",
help="Will not stop or init check if contain git change.",
)
args = parser.parse_args()
return args
lst_ignore_warning = [
"have the same label:",
"odoo.addons.code_generator.extractor_module_file: Ignore next error about"
" ALTER TABLE DROP CONSTRAINT.",
]
lst_ignore_error = [
"fetchmail_notify_error_to_sender",
'odoo.sql_db: bad query: ALTER TABLE "db_backup" DROP CONSTRAINT'
' "db_backup_db_backup_name_unique"',
'ERROR: constraint "db_backup_db_backup_name_unique" of relation'
' "db_backup" does not exist',
'odoo.sql_db: bad query: ALTER TABLE "db_backup" DROP CONSTRAINT'
' "db_backup_db_backup_days_to_keep_positive"',
'ERROR: constraint "db_backup_db_backup_days_to_keep_positive" of relation'
' "db_backup" does not exist',
"odoo.addons.code_generator.extractor_module_file: Ignore next error about"
" ALTER TABLE DROP CONSTRAINT.",
]
def extract_result(result, test_name, lst_error, lst_warning):
lst_log = result[0].split("\n")
for log_line in lst_log:
is_ignore_error = False
if "error" in log_line.lower():
# Remove ignore error
for ignore_error in lst_ignore_error:
if ignore_error in log_line:
is_ignore_error = True
break
if not is_ignore_error:
lst_error.append(log_line)
is_ignore_warning = False
if "warning" in log_line.lower():
# Remove ignore warning
for ignore_warning in lst_ignore_warning:
if ignore_warning in log_line:
is_ignore_warning = True
break
if not is_ignore_warning:
lst_warning.append(log_line)
if result[1]:
lst_error.append(f"Return status error for test {test_name}")
def check_result(task_list, tpl_result):
lst_error = []
lst_warning = []
for i, result in enumerate(tpl_result):
extract_result(
result, task_list[i].cr_code.co_name, lst_error, lst_warning
)
if lst_warning:
print(f"{Fore.YELLOW}{len(lst_warning)} WARNING{Fore.RESET}")
i = 0
for warning in lst_warning:
i += 1
print(f"[{i}]{warning}")
if lst_error:
print(f"{Fore.RED}{len(lst_error)} ERROR{Fore.RESET}")
i = 0
for error in lst_error:
i += 1
print(f"[{i}]{error}")
if lst_error or lst_warning:
str_result = (
f"{Fore.RED}{len(lst_error)} ERROR"
f" {Fore.YELLOW}{len(lst_warning)} WARNING"
)
else:
str_result = f"{Fore.GREEN}SUCCESS 🍰"
print(f"{Fore.BLUE}Summary TEST {str_result}{Fore.RESET}")
def print_log(lst_task, tpl_result):
if len(lst_task) != len(tpl_result):
_logger.error("Different length for log... What happen?")
return
with open(LOG_FILE, "w") as f:
for i, task in enumerate(lst_task):
result = tpl_result[i]
status_str = "PASS" if not result[1] else "FAIL"
f.write(
f"\nTest execution {i + 1} - {status_str} -"
f" {task.cr_code.co_name}\n\n"
)
if result[0]:
f.write(result[0])
f.write("\n")
print(f"Log file {LOG_FILE}")
async def run_command(*args, test_name=None):
# Create subprocess
start_time = time.time()
cmd_str = " ".join(args)
process = await asyncio.create_subprocess_exec(
*args,
# stdout must a pipe to be accessible as process.stdout
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
# Wait for the subprocess to finish
stdout, stderr = await process.communicate()
end_time = time.time()
diff_sec = end_time - start_time
# Return stdout + stderr, returncode
str_out = "\n" + stdout.decode().strip() + "\n" if stdout else ""
str_err = "\n" + stderr.decode().strip() + "\n" if stderr else ""
status_str = "FAIL" if process.returncode else "PASS"
if test_name:
str_output_init = (
f"\n\n{status_str} [{test_name}] [{diff_sec:.3f}s] Execute"
f' "{cmd_str}"\n\n'
)
else:
str_output_init = (
f'\n\n{status_str} [{diff_sec:.3f}s] Execute "{cmd_str}"\n\n'
)
all_output = str_out + str_err
print(str_output_init)
if process.returncode:
lst_error = []
lst_warning = []
extract_result(
(all_output, process.returncode), test_name, lst_error, lst_warning
)
for error in lst_error:
print(f"\t{error}")
for warning in lst_warning:
print(f"\t{warning}")
return str_output_init + all_output, process.returncode
async def test_exec(
path_module_check: str,
generated_module=None,
tested_module=None,
search_class_module=None,
script_after_init_check=None,
lst_init_module_name=None,
test_name=None,
install_path=None,
) -> Tuple[str, int]:
test_result = ""
test_status = 0
if install_path is None:
install_path = path_module_check
# Check code, init module to install
if lst_init_module_name:
for module_name in lst_init_module_name:
res, status = await run_command(
"./script/code_generator/check_git_change_code_generator.sh",
path_module_check,
module_name,
test_name=test_name,
)
test_result += res
test_status += status
# Check code, module to generate
if tested_module:
res, status = await run_command(
"./script/code_generator/check_git_change_code_generator.sh",
path_module_check,
tested_module,
test_name=test_name,
)
test_result += res
test_status += status
# Leave when detect anomaly in check before start
if test_status:
return test_result, test_status
# Execute script before start
if script_after_init_check and not test_status:
res, status = await run_command(script_after_init_check)
test_result += res
test_status += status
is_db_create = False
unique_database_name = f"test_demo_{uuid.uuid4()}"[:63]
if not test_status:
res, status = await run_command(
"./script/db_restore.py",
"--database",
unique_database_name,
test_name=test_name,
)
test_result += res
test_status += status
is_db_create = not status
if not test_status and lst_init_module_name:
# Parallel execution here
# No parallel execution here
str_test = ",".join(lst_init_module_name)
script_name = (
"./script/addons/install_addons_dev.sh"
if tested_module
else "./script/addons/install_addons.sh"
)
res, status = await run_command(
script_name,
unique_database_name,
str_test,
test_name=test_name,
)
test_result += res
test_status += status
if not test_status and search_class_module and generated_module:
path_template_to_generate = os.path.join(
path_module_check, tested_module
)
path_module_to_generate = os.path.join(
path_module_check, search_class_module
)
# Parallel execution here
# No parallel execution here
res, status = await run_command(
"./script/code_generator/search_class_model.py",
"--quiet",
"-d",
path_module_to_generate,
"-t",
path_template_to_generate,
test_name=test_name,
)
test_result += res
test_status += status
if not test_status and tested_module and generated_module:
# Parallel execution here
# No parallel execution here
res, status = await run_command(
"./script/code_generator/install_and_test_code_generator.sh",
unique_database_name,
tested_module,
install_path,
generated_module,
test_name=test_name,
)
test_result += res
test_status += status
if is_db_create:
res, status = await run_command(
"./.venv/bin/python3",
"./odoo/odoo-bin",
"db",
"--drop",
"--database",
unique_database_name,
test_name=test_name,
)
test_result += res
test_status += status
return test_result, test_status
def check_git_change():
"""
return True if success
"""
loop = asyncio.get_event_loop()
task_list = [
run_command(
"./script/code_generator/check_git_change_code_generator.sh",
"./addons/TechnoLibre_odoo-code-generator-template",
test_name="Init check_git_change",
)
]
commands = asyncio.gather(*task_list)
tpl_result = loop.run_until_complete(commands)
status = any([a[1] for a in tpl_result])
loop.close()
return not status
def print_summary_task(task_list):
for task in task_list:
print(task.cr_code.co_name)
# START TEST
async def run_demo_test() -> Tuple[str, int]:
lst_test_name = [
"demo_helpdesk_data",
"demo_internal",
"demo_internal_inherit",
"demo_mariadb_sql_example_1",
"demo_portal",
"demo_website_data",
"demo_website_leaflet",
"demo_website_snippet",
]
res, status = await test_exec(
"./addons/TechnoLibre_odoo-code-generator-template",
lst_init_module_name=lst_test_name,
test_name="demo_test",
)
return res, status
async def run_mariadb_test() -> Tuple[str, int]:
test_result = ""
test_status = 0
# Migrator
res, status = await test_exec(
"./addons/TechnoLibre_odoo-code-generator-template",
generated_module="demo_mariadb_sql_example_1",
tested_module="code_generator_migrator_demo_mariadb_sql_example_1",
script_after_init_check=(
"./script/database/restore_mariadb_sql_example_1.sh"
),
lst_init_module_name=[
"code_generator_portal",
],
test_name="mariadb_test-migrator",
)
test_result += res
test_status += status
# Template
res, status = await test_exec(
"./addons/TechnoLibre_odoo-code-generator-template",
generated_module="code_generator_demo_mariadb_sql_example_1",
tested_module="code_generator_template_demo_mariadb_sql_example_1",
search_class_module="demo_mariadb_sql_example_1",
lst_init_module_name=[
"code_generator_portal",
"demo_mariadb_sql_example_1",
],
test_name="mariadb_test-template",
)
test_result += res
test_status += status
# Code generator
res, status = await test_exec(
"./addons/TechnoLibre_odoo-code-generator-template",
generated_module="demo_mariadb_sql_example_1",
lst_init_module_name=[
"code_generator_portal",
],
tested_module="code_generator_demo_mariadb_sql_example_1",
test_name="mariadb_test-code-generator",
)
test_result += res
test_status += status
return test_result, test_status
async def run_code_generator_multiple_test() -> Tuple[str, int]:
test_result = ""
test_status = 0
lst_generated_module = [
"code_generator_demo",
"demo_helpdesk_data",
"demo_website_data",
"demo_internal",
"demo_portal",
"theme_website_demo_code_generator",
"demo_website_leaflet",
"demo_website_snippet",
]
lst_tested_module = [
"code_generator_demo",
"code_generator_demo_export_helpdesk",
"code_generator_demo_export_website",
"code_generator_demo_internal",
"code_generator_demo_portal",
"code_generator_demo_theme_website",
"code_generator_demo_website_leaflet",
"code_generator_demo_website_snippet",
]
# Multiple
res, status = await test_exec(
"./addons/TechnoLibre_odoo-code-generator-template",
generated_module=",".join(lst_generated_module),
tested_module=",".join(lst_tested_module),
test_name="code_generator_multiple_test",
)
test_result += res
test_status += status
return test_result, test_status
async def run_code_generator_inherit_test() -> Tuple[str, int]:
# TODO can be merge into code_generator_multiple
test_result = ""
test_status = 0
lst_generated_module = [
"demo_internal_inherit",
]
lst_tested_module = [
"code_generator_demo_internal_inherit",
]
# Inherit
res, status = await test_exec(
"./addons/TechnoLibre_odoo-code-generator-template",
generated_module=",".join(lst_generated_module),
tested_module=",".join(lst_tested_module),
test_name="code_generator_inherit_test",
)
test_result += res
test_status += status
return test_result, test_status
async def run_code_generator_auto_backup_test() -> Tuple[str, int]:
test_result = ""
test_status = 0
lst_generated_module = [
"auto_backup",
]
lst_tested_module = [
"code_generator_auto_backup",
]
# Auto-backup
res, status = await test_exec(
"./addons/OCA_server-tools/auto_backup",
generated_module=",".join(lst_generated_module),
tested_module=",".join(lst_tested_module),
test_name="code_generator_auto_backup_test",
)
test_result += res
test_status += status
return test_result, test_status
async def run_code_generator_template_demo_portal_test() -> Tuple[str, int]:
test_result = ""
test_status = 0
# Template
res, status = await test_exec(
"./addons/TechnoLibre_odoo-code-generator-template",
generated_module="code_generator_demo_portal",
tested_module="code_generator_template_demo_portal",
# search_class_module="demo_mariadb_sql_example_1",
lst_init_module_name=[
"demo_portal",
],
test_name="code_generator_template_demo_portal",
)
test_result += res
test_status += status
return test_result, test_status
async def run_code_generator_template_demo_internal_inherit_test() -> Tuple[
str, int
]:
test_result = ""
test_status = 0
# Template
res, status = await test_exec(
"./addons/TechnoLibre_odoo-code-generator-template",
generated_module="code_generator_demo_internal_inherit",
tested_module="code_generator_template_demo_internal_inherit",
# search_class_module="code_generator_demo_internal_inherit",
lst_init_module_name=[
"demo_internal_inherit",
],
test_name="code_generator_template_demo_internal_inherit",
)
test_result += res
test_status += status
return test_result, test_status
async def run_code_generator_template_demo_sysadmin_cron_test() -> Tuple[
str, int
]:
test_result = ""
test_status = 0
# Template
res, status = await test_exec(
"./addons/OCA_server-tools/auto_backup",
generated_module="code_generator_auto_backup",
tested_module="code_generator_template_demo_sysadmin_cron",
# search_class_module="code_generator_demo_internal_inherit",
lst_init_module_name=[
"auto_backup",
],
test_name="code_generator_template_demo_sysadmin_cron",
install_path="./addons/TechnoLibre_odoo-code-generator-template",
)
test_result += res
test_status += status
return test_result, test_status
async def run_helloworld_test() -> Tuple[str, int]:
res, status = await run_command(
"./test/code_generator/hello_world.sh", test_name="helloworld_test"
)
return res, status
def run_all_test() -> None:
task_list = []
task_list.append(run_demo_test())
task_list.append(run_helloworld_test())
task_list.append(run_mariadb_test())
task_list.append(run_code_generator_multiple_test())
task_list.append(run_code_generator_inherit_test())
task_list.append(run_code_generator_auto_backup_test())
task_list.append(run_code_generator_template_demo_portal_test())
task_list.append(run_code_generator_template_demo_internal_inherit_test())
task_list.append(run_code_generator_template_demo_sysadmin_cron_test())
print_summary_task(task_list)
if asyncio.get_event_loop().is_closed():
asyncio.set_event_loop(asyncio.new_event_loop())
loop = asyncio.get_event_loop()
commands = asyncio.gather(*task_list)
tpl_result = loop.run_until_complete(commands)
loop.close()
print_log(task_list, tpl_result)
check_result(task_list, tpl_result)
def main():
config = get_config()
start_time = time.time()
if not config.ignore_init_check_git:
success = check_git_change()
else:
success = True
if success:
run_all_test()
end_time = time.time()
diff_sec = end_time - start_time
# print(f"Time execution {diff_sec:.3f}s")
print(f"Time execution {datetime.timedelta(seconds=diff_sec)}")
return 0
if __name__ == "__main__":
sys.exit(main())

View file

@ -0,0 +1,20 @@
#!/usr/bin/env bash
# $1 new version version, like 3.7.12
input=".python-version"
while IFS= read -r line
do
echo -e "Actual version $line"
sed -i -e "s/$line/$1/g" ./.python-version
sed -i -e "s/$line/$1/g" ./docker/Dockerfile.base
sed -i -e "s/$line/$1/g" ./docker/python-versions.txt
sed -i -e "s/$line/$1/g" ./script/install_locally.sh
sed -i -e "s/$line/$1/g" ./script/install_OSX_dependency.sh
sed -i -e "s/$line/$1/g" ./pyproject.toml
done < "$input"
while IFS= read -r line
do
echo -e "New version $line"
done < "$input"

View file

@ -129,3 +129,5 @@ https://github.com/OCA/maintainer-tools.git,script,master,
https://github.com/TechnoLibre/odoo-code-generator.git,addons,,
https://github.com/TechnoLibre/odoo-code-generator-template.git,addons,,
https://github.com/ERPLibre/ERPLibre_image_db.git,,,
https://github.com/odoo/design-themes.git,addons,,
https://github.com/novacode-nl/odoo-formio.git,addons,,

1 url path revision clone-depth
129 https://github.com/TechnoLibre/odoo-code-generator.git addons
130 https://github.com/TechnoLibre/odoo-code-generator-template.git addons
131 https://github.com/ERPLibre/ERPLibre_image_db.git
132 https://github.com/odoo/design-themes.git addons
133 https://github.com/novacode-nl/odoo-formio.git addons

View file

@ -0,0 +1,18 @@
#!/usr/bin/env bash
Color_Off='\033[0m' # Text Reset
Red='\033[0;31m' # Red
Green='\033[0;32m' # Green
tmp_dir=$(mktemp -d -t "erplibre_code_generator_helloworld-$(date +%Y-%m-%d-%H-%M-%S)-XXXXXXXXXX")
./script/code_generator/new_project.py -m test -d "${tmp_dir}"
MODULE_PATH="${tmp_dir}/test"
if [[ -d "${MODULE_PATH}" ]]; then
echo -e "${Green}SUCCESS${Color_Off} ${MODULE_PATH} exists."
else
echo -e "${Red}ERROR${Color_Off} ${MODULE_PATH} is missing."
fi
rm -rf "${tmp_dir}"