diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..62276b0 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,20 @@ +# Configuration for known file extensions +[*.{css,js,json,less,md,py,rst,sass,scss,xml,yaml,yml}] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[.eslintrc,*.{json,yml,yaml,rst,md}] +indent_size = 2 + +# Do not configure editor for libs and autogenerated content +[*/static/{lib,src/lib}/**,*/static/description/index.html,*/readme/../README.rst] +charset = unset +end_of_line = unset +indent_size = unset +indent_style = unset +insert_final_newline = false +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore index c484315..5ea8a44 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,5 @@ get-poetry.py artifacts wkhtmltox* cache + +node_modules diff --git a/CHANGELOG.md b/CHANGELOG.md index f4848f4..db9a6d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,23 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## Added + +- Selenium script to increase open software client interface and automated some actions. +- FAQ about kill git-daemon + +## Changed + +- Guide to move dev to prod +- Update docker buster to bullseye +- Improve format script to help code-generator +- Improve PyCharm script +- Support OSX for open-terminal + +### Fixed + +- NPM installation locally and not globally + ## [1.5.0] - 2023-07-07 **Migration note** diff --git a/conf/pycharm_default_configuration.csv b/conf/pycharm_default_configuration.csv index 7df43d0..79675da 100644 --- a/conf/pycharm_default_configuration.csv +++ b/conf/pycharm_default_configuration.csv @@ -1,27 +1,31 @@ -name,script_path,parameters,folder -run,./odoo/odoo-bin,--limit-time-real 999999 -c config.conf,run -run_parallel_test,./script/test/run_parallel_test.py,,test -cg_cg,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_code_generator,code_generator -cg_cg_template,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d template -i code_generator_template_code_generator,code_generator_template -code_generator_auto_backup,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_auto_backup,code_generator -code_generator_demo,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo,code_generator -code_generator_demo_export_helpdesk,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_export_helpdesk,code_generator -code_generator_demo_export_website,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_export_website,code_generator -code_generator_demo_export_website_attachments,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_export_website_attachments,code_generator -code_generator_demo_internal,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_internal,code_generator -code_generator_demo_internal_inherit,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_internal_inherit,code_generator -code_generator_demo_mariadb_sql_example_1,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_mariadb_sql_example_1,code_generator -code_generator_demo_portal,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_portal,code_generator -code_generator_demo_theme_website,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_theme_website,code_generator -code_generator_demo_website_leaflet,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_website_leaflet,code_generator -code_generator_demo_website_multiple_snippet,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_website_multiple_snippet,code_generator -code_generator_demo_website_snippet,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_website_snippet,code_generator -code_generator_migrator_demo_mariadb_sql_example_1,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_migrator_demo_mariadb_sql_example_1,code_generator_migrator -code_generator_template_demo_internal,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d template -i code_generator_template_demo_internal,code_generator_template -code_generator_template_demo_internal_inherit,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d template -i code_generator_template_demo_internal_inherit,code_generator_template -code_generator_template_demo_mariadb_sql_example_1,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d template -i code_generator_template_demo_mariadb_sql_example_1,code_generator_template -code_generator_template_demo_portal,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d template -i code_generator_template_demo_portal,code_generator_template -code_generator_template_demo_sysadmin_cron,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d template -i code_generator_template_demo_sysadmin_cron,code_generator_template -code_generator_template_demo_website_multiple_snippet,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d template -i code_generator_template_demo_website_multiple_snippet,code_generator_template -code_generator_template_demo_website_snippet,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d template -i code_generator_template_demo_website_snippet,code_generator_template -create demo internal,./script/code_generator/new_project.py,-m demo_internal -d addons/TechnoLibre_odoo-code-generator-template,new cg project +name,script_path,parameters,folder,default +run,./odoo/odoo-bin,--limit-time-real 999999 -c config.conf,run,True +run_parallel_test,./script/test/run_parallel_test.py,,test, +cg_cg,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_code_generator,code_generator, +cg_cg_template,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d template -i code_generator_template_code_generator,code_generator_template, +code_generator_auto_backup,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_auto_backup,code_generator, +code_generator_demo,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo,code_generator, +code_generator_demo_export_helpdesk,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_export_helpdesk,code_generator, +code_generator_demo_export_website,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_export_website,code_generator, +code_generator_demo_export_website_attachments,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_export_website_attachments,code_generator, +code_generator_demo_internal,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_internal,code_generator, +code_generator_demo_internal_inherit,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_internal_inherit,code_generator, +code_generator_demo_mariadb_sql_example_1,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_mariadb_sql_example_1,code_generator, +code_generator_demo_portal,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_portal,code_generator, +code_generator_demo_theme_website,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_theme_website,code_generator, +code_generator_demo_website_leaflet,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_website_leaflet,code_generator, +code_generator_demo_website_multiple_snippet,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_website_multiple_snippet,code_generator, +code_generator_demo_website_snippet,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_demo_website_snippet,code_generator, +code_generator_migrator_demo_mariadb_sql_example_1,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d code_generator -i code_generator_migrator_demo_mariadb_sql_example_1,code_generator_migrator, +code_generator_template_demo_internal,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d template -i code_generator_template_demo_internal,code_generator_template, +code_generator_template_demo_internal_inherit,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d template -i code_generator_template_demo_internal_inherit,code_generator_template, +code_generator_template_demo_mariadb_sql_example_1,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d template -i code_generator_template_demo_mariadb_sql_example_1,code_generator_template, +code_generator_template_demo_portal,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d template -i code_generator_template_demo_portal,code_generator_template, +code_generator_template_demo_sysadmin_cron,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d template -i code_generator_template_demo_sysadmin_cron,code_generator_template, +code_generator_template_demo_website_multiple_snippet,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d template -i code_generator_template_demo_website_multiple_snippet,code_generator_template, +code_generator_template_demo_website_snippet,./odoo/odoo-bin,--limit-time-real 999999 --no-http -c config.conf --stop-after-init --dev cg -d template -i code_generator_template_demo_website_snippet,code_generator_template, +create demo internal,./script/code_generator/new_project.py,-m demo_internal -d addons/TechnoLibre_odoo-code-generator-template,new cg project, +run_robotlibre,./odoo/odoo-bin,--limit-time-real 999999 -c config.conf -d robotlibre,robotlibre, +run_robotlibre_update,./odoo/odoo-bin,--limit-time-real 999999 --no-http --stop-after-init --dev cg -d robotlibre -i erplibre_devops -u erplibre_devops,robotlibre, +run_robotlibre_generate,./script/code_generator/new_project.py,-f -d ./addons/ERPLibre_erplibre_addons -m erplibre_devops,robotlibre, + diff --git a/conf/pycharm_exclude_folder.txt b/conf/pycharm_exclude_folder.txt index b0e4414..bd0fe12 100644 --- a/conf/pycharm_exclude_folder.txt +++ b/conf/pycharm_exclude_folder.txt @@ -10,3 +10,4 @@ doc/odoo_documentation-user artifacts cache htmlcov +node_modules diff --git a/doc/FAQ.md b/doc/FAQ.md index f94565a..d57238c 100644 --- a/doc/FAQ.md +++ b/doc/FAQ.md @@ -85,6 +85,14 @@ git rebase -i HEAD~4 -x "git commit --amend --author 'Author Name SHELL ["/bin/bash", "-xo", "pipefail", "-c"] @@ -27,6 +27,10 @@ RUN apt-get update \ npm \ xz-utils \ git \ + tree \ + vim \ + htop \ + tig \ wget \ make \ libssl-dev \ @@ -56,8 +60,8 @@ RUN apt-get update \ libncursesw5-dev \ libffi-dev \ uuid-dev \ - && curl -o wkhtmltox.deb -sSL https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.5/wkhtmltox_0.12.5-1.stretch_amd64.deb \ - && echo '7e35a63f9db14f93ec7feeb0fce76b30c08f2057 wkhtmltox.deb' | sha1sum -c - \ + && curl -o wkhtmltox.deb -sSL https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.buster_amd64.deb \ + && echo 'd9f259a67e05e1c221d48b504453645e6c491fab wkhtmltox.deb' | sha1sum -c - \ && apt-get install -y --no-install-recommends ./wkhtmltox.deb \ && rm -rf /var/lib/apt/lists/* wkhtmltox.deb diff --git a/docker/Dockerfile.prod.pkg b/docker/Dockerfile.prod.pkg index 8c2c33c..aaafac7 100644 --- a/docker/Dockerfile.prod.pkg +++ b/docker/Dockerfile.prod.pkg @@ -43,6 +43,10 @@ RUN cd $ODOO_PREFIX && \ ./.venv/bin/poetry --version && \ ./.venv/bin/poetry install +# Install local npm +RUN cd $ODOO_PREFIX && \ + npm install + RUN cd $ODOO_PREFIX && \ head /etc/odoo/odoo.conf && \ ./docker/repo_manifest_gen_org_prefix_path.py $ODOO_PREFIX/addons /etc/odoo/odoo.conf /etc/odoo/odoo.conf && \ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..c3e6e97 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,66 @@ +{ + "name": "erplibre", + "version": "1.5.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "erplibre", + "version": "1.5.0", + "license": "AGPLv3", + "devDependencies": { + "@prettier/plugin-xml": "==2.2.0", + "prettier": "==2.8.8" + } + }, + "node_modules/@prettier/plugin-xml": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@prettier/plugin-xml/-/plugin-xml-2.2.0.tgz", + "integrity": "sha512-UWRmygBsyj4bVXvDiqSccwT1kmsorcwQwaIy30yVh8T+Gspx4OlC0shX1y+ZuwXZvgnafmpRYKks0bAu9urJew==", + "dev": true, + "dependencies": { + "@xml-tools/parser": "^1.0.11", + "prettier": ">=2.4.0" + } + }, + "node_modules/@xml-tools/parser": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@xml-tools/parser/-/parser-1.0.11.tgz", + "integrity": "sha512-aKqQ077XnR+oQtHJlrAflaZaL7qZsulWc/i/ZEooar5JiWj1eLt0+Wg28cpa+XLney107wXqneC+oG1IZvxkTA==", + "dev": true, + "dependencies": { + "chevrotain": "7.1.1" + } + }, + "node_modules/chevrotain": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-7.1.1.tgz", + "integrity": "sha512-wy3mC1x4ye+O+QkEinVJkPf5u2vsrDIYW9G7ZuwFl6v/Yu0LwUuT2POsb+NUWApebyxfkQq6+yDfRExbnI5rcw==", + "dev": true, + "dependencies": { + "regexp-to-ast": "0.5.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/regexp-to-ast": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", + "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..fef8ce6 --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "erplibre", + "description": "Easy installation of Odoo", + "version": "1.5.0", + "license": "AGPLv3", + "homepage": "https://erplibre.ca", + "devDependencies": { + "@prettier/plugin-xml": "==2.2.0", + "prettier": "==2.8.8" + } +} diff --git a/script/code_generator/install_and_test_code_generator.sh b/script/code_generator/install_and_test_code_generator.sh index b43919b..57267d8 100755 --- a/script/code_generator/install_and_test_code_generator.sh +++ b/script/code_generator/install_and_test_code_generator.sh @@ -49,7 +49,17 @@ cd "$3" || exit 1 git checkout -- "*.po*" cd - || exit 1 -./script/maintenance/black.sh "$3" +#./script/maintenance/format.sh "$3" +# Itéré pour chaque module et formater +IFS=',' +# Diviser la chaîne en un tableau +read -ra elements <<<"$4" +# Itérer sur les éléments +for element in "${elements[@]}"; do + echo "Format ${3}/${element}" + ./script/maintenance/format.sh "${3}/${element}" +done + echo "TEST ${2}" ./script/code_generator/check_git_change_code_generator.sh "$3" retVal=$? diff --git a/script/code_generator/new_project.py b/script/code_generator/new_project.py index d831e32..a26bdf9 100755 --- a/script/code_generator/new_project.py +++ b/script/code_generator/new_project.py @@ -57,6 +57,11 @@ def get_config(): required=True, help="Module name to create", ) + parser.add_argument( + "--odoo_config", + default="./config.conf", + help="Odoo config path", + ) parser.add_argument( "--config", help="""Configuration to create models with fields and type. JSON style. @@ -116,12 +121,14 @@ class ProjectManagement: keep_bd_alive=False, coverage=False, config="", + odoo_config="./config.conf", ): self.force = force self._coverage = coverage self.keep_bd_alive = keep_bd_alive self.msg_error = "" self.has_config_update = False + self.odoo_config = odoo_config self.module_directory = module_directory if not os.path.exists(self.module_directory): @@ -522,7 +529,7 @@ class ProjectManagement: os.system(cmd) # Validate - if not os.path.exists(template_path): + if not os.path.exists(module_path): _logger.error(f"Module not exists '{module_path}'") return False else: @@ -532,7 +539,7 @@ class ProjectManagement: def update_config(self): config = configparser.ConfigParser() - config.read("./config.conf") + config.read(self.odoo_config) addons_path = config.get("options", "addons_path") lst_addons_path = addons_path.split(",") lst_directory = list( @@ -579,6 +586,7 @@ def main(): keep_bd_alive=config.keep_bd_alive, coverage=config.coverage, config=config.config, + odoo_config=config.odoo_config, ) if project.msg_error: return -1 diff --git a/script/code_generator/search_class_model.py b/script/code_generator/search_class_model.py index 266bf28..795046a 100755 --- a/script/code_generator/search_class_model.py +++ b/script/code_generator/search_class_model.py @@ -212,8 +212,8 @@ def main(): 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}") + # Call format all file + os.system(f"./script/maintenance/format.sh {hooks_file_path}") return 0 diff --git a/script/ide/pycharm_configuration.py b/script/ide/pycharm_configuration.py index 119492a..d5d22bb 100755 --- a/script/ide/pycharm_configuration.py +++ b/script/ide/pycharm_configuration.py @@ -38,7 +38,7 @@ def get_config(): parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description="""\ - Manipulate configuration for your IDE Pycharm about ERPLibre. + Manipulate configuration for your IDE Pycharm about ERPLibre. This script manage only Python configuration, other configuration will be ignore. """, epilog="""\ @@ -65,10 +65,22 @@ def get_config(): action="store_true", help="Initialize minimum configuration for Pycharm.", ) + parser.add_argument( + "--overwrite", + action="store_true", + help="Remove old data and replace it.", + ) args = parser.parse_args() - if args.init or args.list_configuration or args.list_configuration_full: + if ( + args.init + or args.list_configuration + or args.list_configuration_full + or args.overwrite + ): args.configuration = True + if args.overwrite: + args.init = True else: args.configuration = False @@ -78,6 +90,7 @@ def get_config(): def main(): has_execute = False config = get_config() + _logger.info(f"Work on directory {os.getcwd()}") # TODO modifier vcs.xml pour le mapping des répertoires git @@ -120,6 +133,7 @@ def main(): def read_xml_and_execute(file_name, cb, name, config): + _logger.info(f"Pycharm configuration on file {file_name}") with open(file_name) as xml: xml_as_string = xml.read() dct_project_xml = xmltodict.parse(xml_as_string) @@ -133,8 +147,7 @@ def read_xml_and_execute(file_name, cb, name, config): xml.write(xml_format) _logger.info(f"File {file_name} has been write.") subprocess.call( - "prettier --tab-width 2 --print-width 999999 --write" - f" '{file_name}'", + f"script/maintenance/prettier_xml.sh '{file_name}'", shell=True, ) else: @@ -150,6 +163,28 @@ def add_configuration(dct_xml, file_name, config): not bool(lst_component), f"Missing 'project/component' into {file_name}", ) + # Add python configuration + dct_component_py_conf = [ + a + for a in lst_component + if a.get("@name") == "PyConsoleOptionsProvider" + ] + if dct_component_py_conf: + # TODO check and force value + pass + else: + lst_component.append( + { + "@name": "PyConsoleOptionsProvider", + "option": { + "@name": "myShowDebugConsoleByDefault", + "@value": "false", + }, + } + ) + has_change = True + + # Add configuration dct_component = [ a for a in lst_component if a.get("@name") == "RunManager" ] @@ -157,12 +192,12 @@ def add_configuration(dct_xml, file_name, config): # Create it dct_component = { "@name": "RunManager", - "@selected": "Python.pycharm_configuration", - "recent_temporary": { - "list": { - "item": {"@itemvalue": "Python.pycharm_configuration"} - } - }, + # "@selected": "Python.pycharm_configuration", + # "recent_temporary": { + # "list": { + # "item": {"@itemvalue": "Python.pycharm_configuration"} + # } + # }, "configuration": [], "list": {"item": []}, } @@ -219,116 +254,124 @@ def add_configuration(dct_xml, file_name, config): for conf in lst_configuration: print(f"\t{conf}") - if config.init: - if os.path.isfile(PATH_DEFAULT_CONFIGURATION): - with open(PATH_DEFAULT_CONFIGURATION) as txt: - for default_conf in csv.DictReader(txt): - conf_name = default_conf.get("name") - conf_folder = default_conf.get("folder") - conf_script_path = default_conf.get("script_path") - conf_script_path_replace = ( - conf_script_path - if not conf_script_path.startswith("./") - else f"$PROJECT_DIR${conf_script_path[1:]}" + last_default = None + if not config.init: + return has_change + if not os.path.isfile(PATH_DEFAULT_CONFIGURATION): + _logger.error(f"Cannot read file '{PATH_DEFAULT_CONFIGURATION}'") + return has_change + with open(PATH_DEFAULT_CONFIGURATION) as txt: + for default_conf in csv.DictReader(txt): + conf_name = default_conf.get("name") + conf_folder = default_conf.get("folder") + conf_script_path = default_conf.get("script_path") + conf_default = bool(default_conf.get("default")) + if conf_default: + last_default = f"Python.{conf_name}" + conf_script_path_replace = ( + conf_script_path + if not conf_script_path.startswith("./") + else f"$PROJECT_DIR${conf_script_path[1:]}" + ) + conf_parameter = default_conf.get("parameters") + s_unique_key = ( + f"d {conf_folder} s {conf_script_path} p {conf_parameter}" + ) + if ( + config.overwrite + or s_unique_key not in lst_unique_configuration + ): + # add it! + if not config.overwrite and conf_name in lst_configuration: + _logger.error( + f"Cannot add configuration name '{conf_name}'," + " already exist. Delete it manually." ) - conf_parameter = default_conf.get("parameters") - s_unique_key = ( - f"d {conf_folder} s" - f" {conf_script_path} p" - f" {conf_parameter}" + else: + has_change = True + lst_xml_configuration_name.append( + {"@itemvalue": f"Python.{conf_name}"} ) - if s_unique_key not in lst_unique_configuration: - # add it! - if conf_name in lst_configuration: - _logger.error( - f"Cannot add configuration name '{conf_name}'," - " already exist. Delete it manually." - ) - else: - has_change = True - lst_xml_configuration_name.append( - {"@itemvalue": f"Python.conf_name"} - ) - conf_full = { - "@name": conf_name, - "@type": "PythonConfigurationType", - "@factoryName": "Python", - "module": {"@name": PROJECT_NAME}, - "option": [ - { - "@name": "INTERPRETER_OPTIONS", - "@value": "", - }, - {"@name": "PARENT_ENVS", "@value": "true"}, - { - "@name": "SDK_HOME", - "@value": ( - "$PROJECT_DIR$/.venv/bin/python" - ), - }, - { - "@name": "WORKING_DIRECTORY", - "@value": "$PROJECT_DIR$", - }, - { - "@name": "IS_MODULE_SDK", - "@value": "false", - }, - { - "@name": "ADD_CONTENT_ROOTS", - "@value": "true", - }, - { - "@name": "ADD_SOURCE_ROOTS", - "@value": "true", - }, - { - "@name": "SCRIPT_NAME", - "@value": conf_script_path_replace, - }, - { - "@name": "PARAMETERS", - "@value": conf_parameter, - }, - { - "@name": "SHOW_COMMAND_LINE", - "@value": "false", - }, - { - "@name": "EMULATE_TERMINAL", - "@value": "false", - }, - { - "@name": "MODULE_MODE", - "@value": "false", - }, - { - "@name": "REDIRECT_INPUT", - "@value": "false", - }, - {"@name": "INPUT_FILE", "@value": ""}, - ], - "envs": { - "env": { - "@name": "PYTHONUNBUFFERED", - "@value": "1", - } - }, - "EXTENSION": { - "@ID": "PythonCoverageRunConfigurationExtension", - "@runner": "coverage.py", - }, - "method": {"@v": "2"}, + conf_full = { + "@name": conf_name, + "@type": "PythonConfigurationType", + "@factoryName": "Python", + "module": {"@name": PROJECT_NAME}, + "option": [ + { + "@name": "INTERPRETER_OPTIONS", + "@value": "", + }, + {"@name": "PARENT_ENVS", "@value": "true"}, + { + "@name": "SDK_HOME", + "@value": "$PROJECT_DIR$/.venv/bin/python", + }, + { + "@name": "WORKING_DIRECTORY", + "@value": "$PROJECT_DIR$", + }, + { + "@name": "IS_MODULE_SDK", + "@value": "false", + }, + { + "@name": "ADD_CONTENT_ROOTS", + "@value": "true", + }, + { + "@name": "ADD_SOURCE_ROOTS", + "@value": "true", + }, + { + "@name": "SCRIPT_NAME", + "@value": conf_script_path_replace, + }, + { + "@name": "PARAMETERS", + "@value": conf_parameter, + }, + { + "@name": "SHOW_COMMAND_LINE", + "@value": "false", + }, + { + "@name": "EMULATE_TERMINAL", + "@value": "false", + }, + { + "@name": "MODULE_MODE", + "@value": "false", + }, + { + "@name": "REDIRECT_INPUT", + "@value": "false", + }, + {"@name": "INPUT_FILE", "@value": ""}, + ], + "envs": { + "env": { + "@name": "PYTHONUNBUFFERED", + "@value": "1", } - if conf_folder: - conf_full["@folderName"] = conf_folder - lst_configuration_full.insert(0, conf_full) - else: - _logger.info( - f"Configuration already exist: '{s_unique_key}'" - ) - else: - _logger.error(f"Cannot read file '{PATH_DEFAULT_CONFIGURATION}'") + }, + "EXTENSION": { + "@ID": "PythonCoverageRunConfigurationExtension", + "@runner": "coverage.py", + }, + "method": {"@v": "2"}, + } + if conf_folder: + conf_full["@folderName"] = conf_folder + lst_configuration_full.insert(0, conf_full) + else: + _logger.info(f"Configuration already exist: '{s_unique_key}'") + + if last_default: + dct_component["@selected"] = last_default + dct_component["recent_temporary"] = { + "list": {"item": {"@itemvalue": last_default}} + } return has_change diff --git a/script/install/install_OSX_dependency.sh b/script/install/install_OSX_dependency.sh index f82bed9..1728a08 100755 --- a/script/install/install_OSX_dependency.sh +++ b/script/install/install_OSX_dependency.sh @@ -35,8 +35,7 @@ echo "\n---- Installing nodeJS NPM and rtlcss for LTR support ----" brew install nodejs npm openssl sudo npm install -g rtlcss sudo npm install -g less -sudo npm install -g prettier -sudo npm install -g prettier @prettier/plugin-xml +npm install echo 'export PATH="/usr/local/opt/openssl@1.1/bin:$PATH"' >> ~/.zshrc diff --git a/script/install/install_debian_dependency.sh b/script/install/install_debian_dependency.sh index d297c5a..aaac1f0 100755 --- a/script/install/install_debian_dependency.sh +++ b/script/install/install_debian_dependency.sh @@ -89,74 +89,46 @@ if [[ $retVal -ne 0 ]]; then fi echo -e "\n---- Installing nodeJS NPM and rtlcss for LTR support ----" +sudo apt-get update +sudo apt-get install -y ca-certificates curl gnupg +sudo mkdir -p /etc/apt/keyrings +curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg + if [ "18.04" == "${UBUNTU_VERSION}" ]; then sudo apt remove nodeJS npm - curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.2/install.sh | bash - chmod +x ~/.nvm/nvm.sh - . $NVM_DIR/nvm.sh && nvm install 16.15.1 - retVal=$? - if [[ $retVal -ne 0 ]]; then - echo "nvm installation error." - exit 1 - fi - source ~/.bashrc - npm install npm@latest -g - retVal=$? - if [[ $retVal -ne 0 ]]; then - echo "npm install npm lastest installation error." - exit 1 - fi - npm install -g rtlcss - retVal=$? - if [[ $retVal -ne 0 ]]; then - echo "npm install rtlcss installation error." - exit 1 - fi - npm install -g less - retVal=$? - if [[ $retVal -ne 0 ]]; then - echo "npm install less installation error." - exit 1 - fi + NODE_MAJOR=16 else - curl -fsSL https://deb.nodesource.com/setup_current.x | sudo -E bash - - sudo apt-get install -y nodejs - retVal=$? - if [[ $retVal -ne 0 ]]; then - echo "apt-get nodejs installation error." - exit 1 - fi - sudo npm install npm@latest -g - retVal=$? - if [[ $retVal -ne 0 ]]; then - echo "npm install npm lastest installation error." - exit 1 - fi - sudo npm install -g rtlcss - retVal=$? - if [[ $retVal -ne 0 ]]; then - echo "npm install rtlcss installation error." - exit 1 - fi - sudo npm install -g less - retVal=$? - if [[ $retVal -ne 0 ]]; then - echo "npm install less installation error." - exit 1 - fi + NODE_MAJOR=20 +fi + +echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list +sudo apt-get update +sudo apt-get install nodejs -y + +sudo npm install npm@latest -g +retVal=$? +if [[ $retVal -ne 0 ]]; then + echo "npm install npm lastest installation error." + exit 1 +fi +sudo npm install -g rtlcss +retVal=$? +if [[ $retVal -ne 0 ]]; then + echo "npm install rtlcss installation error." + exit 1 +fi +sudo npm install -g less +retVal=$? +if [[ $retVal -ne 0 ]]; then + echo "npm install less installation error." + exit 1 fi echo -e "\n---- Test tool ----" -sudo npm install -g prettier +npm install retVal=$? if [[ $retVal -ne 0 ]]; then - echo "npm install prettier installation error." - exit 1 -fi -sudo npm install -g prettier @prettier/plugin-xml -retVal=$? -if [[ $retVal -ne 0 ]]; then - echo "npm install prettier plugin-xml installation error." + echo "npm install prettier + plugin-xml installation error." exit 1 fi diff --git a/script/install/install_locally.sh b/script/install/install_locally.sh index 0e415d0..79275fb 100755 --- a/script/install/install_locally.sh +++ b/script/install/install_locally.sh @@ -75,6 +75,7 @@ if [[ ! -d ${VENV_PATH} ]]; then exit 1 fi fi +source ./.venv/bin/activate #if [[ ! -d "${POETRY_PATH}" ]]; then # # Delete directory ~/.poetry and .venv to force update to new version diff --git a/script/install/install_locally_dev.sh b/script/install/install_locally_dev.sh index 98dfbcb..f7deef6 100755 --- a/script/install/install_locally_dev.sh +++ b/script/install/install_locally_dev.sh @@ -17,6 +17,8 @@ if [[ $retVal -ne 0 ]]; then exit 1 fi +npm install + ## Install maintainer-tools #cd script/OCA_maintainer-tools || exit ## virtualenv is not installed by default diff --git a/script/maintenance/black.sh b/script/maintenance/black.sh index 2bc6f89..630f61a 100755 --- a/script/maintenance/black.sh +++ b/script/maintenance/black.sh @@ -2,7 +2,7 @@ # This will format all python file # argument 1: directory or file to format source ./.venv/bin/activate -black -l 79 --preview -t py37 $@ +black -l 79 --preview -t py37 "$@" retVal=$? if [[ $retVal -ne 0 ]]; then echo "Error black format" diff --git a/script/maintenance/format.sh b/script/maintenance/format.sh new file mode 100755 index 0000000..7b2bf7e --- /dev/null +++ b/script/maintenance/format.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +cmd1="./script/maintenance/format_python.sh \"$*\"" +cmd2="find \"$*\" -type f -not -path \"*/not_supported_files/*\" -name '*.xml' -print0 | parallel -0 ./script/maintenance/prettier_xml.sh {}" +cmd3="find \"$*\" -type f -not -path \"*/not_supported_files/*\" -name '*.js' -print0 | parallel -0 ./script/maintenance/prettier.sh {}" +cmd4="find \"$*\" -type f -not -path \"*/not_supported_files/*\" -name '*.css' -print0 | parallel -0 ./script/maintenance/prettier.sh {}" +cmd5="find \"$*\" -type f -not -path \"*/not_supported_files/*\" -name '*.scss' -print0 | parallel -0 ./script/maintenance/prettier.sh {}" +cmd6="find \"$*\" -type f -not -path \"*/not_supported_files/*\" -name '*.html' -print0 | parallel -0 ./script/maintenance/prettier.sh {}" +parallel ::: "$cmd1" "$cmd2" "$cmd3" "$cmd4" "$cmd5" "$cmd6" diff --git a/script/maintenance/format_python.sh b/script/maintenance/format_python.sh index 75a67f1..f17ec1e 100755 --- a/script/maintenance/format_python.sh +++ b/script/maintenance/format_python.sh @@ -1,3 +1,5 @@ #!/usr/bin/env bash -.venv/bin/isort --profile black -l 79 "$@" +source ./.venv/bin/activate +isort --profile black -l 79 "$@" +#./.venv/bin/isort --profile black -l 79 "$@" ./script/maintenance/black.sh "$@" diff --git a/script/maintenance/prettier.sh b/script/maintenance/prettier.sh index b7f22c3..4494ecc 100755 --- a/script/maintenance/prettier.sh +++ b/script/maintenance/prettier.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # This will format all js,css,html # argument 1: directory or file to format -prettier --write $@ +./node_modules/.bin/prettier --tab-width 4 --print-width 120 --no-bracket-spacing --write "$@" retVal=$? if [[ $retVal -ne 0 ]]; then echo "Error prettier format" diff --git a/script/maintenance/prettier_xml.sh b/script/maintenance/prettier_xml.sh index 2b0890f..853484e 100755 --- a/script/maintenance/prettier_xml.sh +++ b/script/maintenance/prettier_xml.sh @@ -4,14 +4,14 @@ STR_ARG="'$*'" if [[ "${STR_ARG}" = *"/data/"* ]]; then # Need to keep width with data, else add corrupted string data - prettier --xml-whitespace-sensitivity "ignore" --prose-wrap always --tab-width 4 --no-bracket-spacing --print-width 999999999 --write $@ + ./node_modules/.bin/prettier --plugin=@prettier/plugin-xml --xml-whitespace-sensitivity "ignore" --prose-wrap always --tab-width 4 --no-bracket-spacing --print-width 999999999 --write "$@" else - prettier --xml-whitespace-sensitivity "ignore" --prose-wrap always --tab-width 4 --no-bracket-spacing --print-width 120 --write $@ + ./node_modules/.bin/prettier --plugin=@prettier/plugin-xml --xml-whitespace-sensitivity "ignore" --prose-wrap always --tab-width 4 --no-bracket-spacing --print-width 120 --write "$@" # strict xml-whitespace-sensitivity will keep space alignement #prettier --xml-whitespace-sensitivity "strict" --prose-wrap always --tab-width 4 --no-bracket-spacing --print-width 120 --write $@ fi retVal=$? if [[ $retVal -ne 0 ]]; then - echo "Error prettier format" + echo "Error prettier-xml format" exit 1 fi diff --git a/script/manifest/update_manifest_local_dev.sh b/script/manifest/update_manifest_local_dev.sh index 513aace..af4ad39 100755 --- a/script/manifest/update_manifest_local_dev.sh +++ b/script/manifest/update_manifest_local_dev.sh @@ -8,7 +8,7 @@ git daemon --base-path=. --export-all --reuseaddr --informative-errors --verbose & DAEMON_PID=$! -./.venv/repo init -u git://127.0.0.1:9418/ -b $(git rev-parse --verify HEAD) -m ${EL_MANIFEST_DEV} +./.venv/repo init -u git://127.0.0.1:9418/ -b $(git rev-parse --verify HEAD) -m ${EL_MANIFEST_DEV} "$@" ./.venv/repo sync -v --force-sync -m ${EL_MANIFEST_DEV} kill ${DAEMON_PID} diff --git a/script/open_terminal_code_generator.sh b/script/open_terminal_code_generator.sh index de4b3af..b048a39 100755 --- a/script/open_terminal_code_generator.sh +++ b/script/open_terminal_code_generator.sh @@ -1,26 +1,47 @@ #!/usr/bin/env bash # Open a new gnome-terminal with different path on new tab -working_path=`readlink -f .` +working_path=$(readlink -f .) paths=( -"${working_path}/" -"${working_path}/addons/TechnoLibre_odoo-code-generator" -"${working_path}/addons/TechnoLibre_odoo-code-generator-template" -"${working_path}/addons/ERPLibre_erplibre_addons" -"${working_path}/addons/OCA_server-tools" + "${working_path}/" +# "${working_path}/addons/TechnoLibre_odoo-code-generator" +# "${working_path}/addons/TechnoLibre_odoo-code-generator-template" + "${working_path}/addons/ERPLibre_erplibre_addons" +# "${working_path}/addons/OCA_server-tools" ) -cmd_before="cd " -# when change directory, open a new tab with command to execute -cmd_after=";gnome-terminal --tab -- bash -c 'git status;bash';" -#cmd_after=";gnome-terminal --tab;" -LONGCMD="" -for t in "${paths[@]}"; do - LONGCMD+=${cmd_before}${t}${cmd_after} -done +first_iteration=true +if [[ "${OSTYPE}" == "linux-gnu" ]]; then + cmd_before="cd " + cmd_after_first=";gnome-terminal --tab -- bash -c 'source ./.venv/bin/activate;git status;bash';" + cmd_after=";gnome-terminal --tab -- bash -c 'git status;bash';" + LONGCMD="" + for t in "${paths[@]}"; do + if $first_iteration; then + LONGCMD+="${cmd_before}${t}${cmd_after_first}" + first_iteration=false + else + LONGCMD+="${cmd_before}${t}${cmd_after}" + fi + done + gnome-terminal --window -- bash -c "${LONGCMD}" +elif [[ "${OSTYPE}" == "darwin"* ]]; then + paths=("${paths[@]:1}") -#echo $LONGCMD + # Initialisation de la commande osascript + osascript_command="osascript -e 'tell application \"Terminal\"'" -# Open all terminal from paths list -#echo "gnome-terminal --window -- bash -c \"${LONGCMD}\"" -gnome-terminal --window -- bash -c "${LONGCMD}" + # Boucle pour ajouter des commandes pour ouvrir de nouveaux onglets et exécuter les scripts batch + for t in "${paths[@]}"; do + if $first_iteration; then + osascript_command+=" -e 'tell application \"System Events\" to keystroke \"t\" using {command down}' -e 'delay 0.1' -e 'do script \"cd ${t}; source ./.venv/bin/activate; git status\" in front window'" + first_iteration=false + else + osascript_command+=" -e 'tell application \"System Events\" to keystroke \"t\" using {command down}' -e 'delay 0.1' -e 'do script \"cd ${t}; git status\" in front window'" + fi + done + osascript_command+=" -e 'end tell'" + + # Exécution de la commande osascript + eval "$osascript_command" +fi diff --git a/script/selenium/__init__.py b/script/selenium/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/script/selenium/darkreader-firefox.xpi b/script/selenium/darkreader-firefox.xpi new file mode 100644 index 0000000..a89e099 Binary files /dev/null and b/script/selenium/darkreader-firefox.xpi differ diff --git a/script/selenium/install.md b/script/selenium/install.md new file mode 100644 index 0000000..448a05d --- /dev/null +++ b/script/selenium/install.md @@ -0,0 +1,5 @@ +sudo apt install libcairo2-dev python3-dev pkg-config libxt-dev libgirepository1.0-dev + +pip install pycairo PyGObject + +https://github.com/szemate/pyselenium-video-recorder diff --git a/script/selenium/odoo_debug-4.0.xpi b/script/selenium/odoo_debug-4.0.xpi new file mode 100644 index 0000000..588206f Binary files /dev/null and b/script/selenium/odoo_debug-4.0.xpi differ diff --git a/script/selenium/selenium_video.py b/script/selenium/selenium_video.py new file mode 100644 index 0000000..a0ea83c --- /dev/null +++ b/script/selenium/selenium_video.py @@ -0,0 +1,113 @@ +"""Video recorder for Selenium WebDriver.""" + +import threading + +import gi + +gi.require_version("Gst", "1.0") +from gi.repository import Gst + +Gst.init(None) + + +class VideoRecorder(object): + """Record video of a Selenium test run in WebM format through repeated + screenshot captures. + + :type driver: selenium.webdriver.Remote + :param filename: Path of the video file to create, or `None` to view live + video output. + :param framerate: Rate of screenshot capture as fraction [fps]. + :param width: Crop screenshots to this width [pixels]. + :param height: Crop screenshots to this height [pixels]. + """ + + def __init__( # pylint: disable=too-many-arguments + self, + driver, + filename="video.webm", + framerate="25/1", + width=None, + height=None, + ): + self.driver = driver + _patch_driver(self.driver) + + if filename and not filename.endswith(".webm"): + filename += ".webm" + + caps = ["video/x-raw", "framerate={}".format(framerate)] + if width: + caps.append("width={}".format(width)) + if height: + caps.append("height={}".format(height)) + + elements = [ + "appsrc name=src is-live=true do-timestamp=true caps=image/png", + "pngdec", + "videoconvert", + "videorate", + "videocrop name=crop", + ",".join(caps), + "queue", + ] + if filename: + elements += [ + "vp8enc", + "webmmux", + "filesink location={}".format(filename), + ] + else: + elements.append("autovideosink sync=false") + self._pipeline = Gst.parse_launch(" ! ".join(elements)) + + self._appsrc = self._pipeline.get_by_name("src") + self._appsrc.connect("need-data", self._push_screenshot) + + videocrop = self._pipeline.get_by_name("crop") + if width: + videocrop.set_property("right", -1) # Auto-crop + if height: + videocrop.set_property("bottom", -1) # Auto-crop + + def start(self): + """Start video recording.""" + self._pipeline.set_state(Gst.State.PLAYING) + + def stop(self): + """Stop video recording.""" + self._appsrc.emit("end-of-stream") + self._pipeline.set_state(Gst.State.NULL) + + def _push_screenshot(self, *_): + """Emit a WebDriver screenshot from appsrc.""" + self._appsrc.emit( + "push-buffer", + Gst.Buffer.new_wrapped(self.driver.get_screenshot_as_png()), + ) + + +def VideoViewer(*args, **kwargs): + """Shorthand for `VideoRecorder(filename=None)`. + + Useful with PhantomJS. + """ + kwargs["filename"] = None + return VideoRecorder(*args, **kwargs) + + +def _patch_driver(driver): + """Prevent failures caused by concurrent connections to the remote + WebDriver. + + Another option would be to use a WebDriver proxy. Monkey patching `driver` + is simpler, though more hacky. + """ + lock = threading.Lock() + execute_unsafe = driver.execute + + def execute_safe(driver_command, params=None): + with lock: + return execute_unsafe(driver_command, params) + + driver.execute = execute_safe diff --git a/script/selenium/web_login.py b/script/selenium/web_login.py new file mode 100755 index 0000000..f5d2ba6 --- /dev/null +++ b/script/selenium/web_login.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +from selenium import webdriver +from selenium.webdriver.common.by import By + +# Configuration pour lancer Firefox en mode de navigation privée +firefox_options = webdriver.FirefoxOptions() +firefox_options.add_argument("--private") + +# Définissez la préférence pour les notifications de bureau +# 1 signifie "autoriser", 2 signifie "bloquer" +firefox_options.set_preference("permissions.default.desktop-notification", 1) + +# Créez une instance du navigateur Firefox avec les options de navigation privée +driver = webdriver.Firefox(options=firefox_options) + +# Ouvrez la page web +driver.get("http://127.0.0.1:8069/web") + +# Trouvez les éléments du formulaire +courriel_input = driver.find_element(By.NAME, "login") +mot_de_passe_input = driver.find_element(By.NAME, "password") +try: + connexion_button = driver.find_element( + By.XPATH, + "/html/body/div/div/div/form/div[3]/button" + # '//button[contains(text(), "Log in")]' + ) +except Exception: + connexion_button = driver.find_element( + By.XPATH, + "/html/body/div/main/div/form/div[3]/button" + # '//button[contains(text(), "Connexion")]' + ) + +# Remplissez le courriel et le mot de passe +courriel_input.send_keys("admin") +mot_de_passe_input.send_keys("admin") + +# Cliquez sur le bouton "Connexion" +connexion_button.click() + +# Fermez le navigateur +# driver.quit() diff --git a/script/selenium/web_login_open_me_devops.py b/script/selenium/web_login_open_me_devops.py new file mode 100755 index 0000000..3c9b6e8 --- /dev/null +++ b/script/selenium/web_login_open_me_devops.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import os +import sys + +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.support.ui import WebDriverWait + +private_mode = True +record_mode = False +dark_reader_mode = True + + +def click(driver, xpath, time=5): + wait = WebDriverWait(driver, time) + button = wait.until( + EC.element_to_be_clickable( + ( + By.XPATH, + xpath, + ) + ) + ) + button.click() + + +if record_mode: + new_path = os.path.normpath( + os.path.join(os.path.dirname(__file__), "..", "..") + ) + sys.path.append(new_path) + from script.selenium.selenium_video import VideoRecorder + +# Configuration pour lancer Firefox en mode de navigation privée +firefox_options = webdriver.FirefoxOptions() +if private_mode: + firefox_options.add_argument("--private") + +# Définissez la préférence pour les notifications de bureau +# 1 signifie "autoriser", 2 signifie "bloquer" +firefox_options.set_preference("permissions.default.desktop-notification", 1) + +# Créez une instance du navigateur Firefox avec les options de navigation privée +driver = webdriver.Firefox(options=firefox_options) + +# Ajout de l'enregistrement +if record_mode: + video_recorder = VideoRecorder(driver) +else: + video_recorder = None + +# Install DarkReader to help my eyes +# TODO do a script to check if it's the last version +if dark_reader_mode: + driver.install_addon( + "./script/selenium/darkreader-firefox.xpi", temporary=True + ) + driver.install_addon( + "./script/selenium/odoo_debug-4.0.xpi", temporary=True + ) + +if private_mode and dark_reader_mode: + driver.get("about:addons") + # Enable Dark Reader into incognito + click(driver, "/html/body/div/div[1]/categories-box/button[2]") + click( + driver, + "/html/body/div/div[2]/div/addon-list/section[1]/addon-card/div/div/div/div/button", + ) + click( + driver, + "/html/body/div/div[2]/div/addon-list/section[1]/addon-card/div/addon-options/panel-list/panel-item[5]", + ) + click( + driver, + "/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[5]/div/label[1]/input", + ) + + # Enable Odoo_debug into incognito + # Back + click(driver, "/html/body/div/div[2]/addon-page-header/div/div[2]/button") + click( + driver, + "/html/body/div/div[2]/div/addon-list/section[1]/addon-card[2]/div/div/div/div/button", + ) + click( + driver, + "/html/body/div/div[2]/div/addon-list/section[1]/addon-card[2]/div/addon-options/panel-list/panel-item[5]", + ) + click( + driver, + "/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[5]/div/label[1]/input", + ) + +# Ouvrez la page web +driver.get("http://127.0.0.1:8069/web") + +# Close tab opening by DarkReader +if not private_mode and dark_reader_mode: + driver.switch_to.window(driver.window_handles[-1]) + driver.close() + driver.switch_to.window(driver.window_handles[0]) + +# Démarrer l'enregistrement +if record_mode: + video_recorder.start() + +# Trouvez les éléments du formulaire +courriel_input = driver.find_element(By.NAME, "login") +mot_de_passe_input = driver.find_element(By.NAME, "password") +try: + connexion_button = driver.find_element( + By.XPATH, + "/html/body/div/div/div/form/div[3]/button" + # '//button[contains(text(), "Log in")]' + ) +except Exception: + connexion_button = driver.find_element( + By.XPATH, + "/html/body/div/main/div/form/div[3]/button" + # '//button[contains(text(), "Connexion")]' + ) + +# Remplissez le courriel et le mot de passe +courriel_input.send_keys("admin") +mot_de_passe_input.send_keys("admin") + +# Cliquez sur le bouton "Connexion" +connexion_button.click() + +# Attendez que l'élément soit cliquable +wait = WebDriverWait(driver, 5) +# menu_toggle = wait.until( +# EC.element_to_be_clickable((By.XPATH, "/html/body/header/nav/ul[1]/li/a")) +# ) +# +# # Cliquez sur l'élément +# menu_toggle.click() +# +# # Attendez que le lien soit cliquable +# menu_item = wait.until( +# EC.element_to_be_clickable( +# ( +# By.XPATH, +# "/html/body/header/nav/ul[1]/li/div/a[2]", +# ) +# ) +# ) + +# Open View +click(driver, "/html/body/header/nav/div/div[1]/div[2]/div/div/div/ul/li[2]/a") +click(driver, "/html/body/div[1]/main/div[2]/div/div/table/tbody/tr[1]/td[2]") + +# Arrêter l'enregistrement +if record_mode: + video_recorder.stop() + +# Open conversation chat +# conversation_button = driver.find_element(By.XPATH, '/html/body/header/nav/ul[3]/li[2]/a') +# conversation_button.click() + +# Close bot chat +# conversation_button = driver.find_element(By.XPATH, '/html/body/div[3]/div[1]/span[2]/a[2]') +# conversation_button.click() + +# Fermez le navigateur +# driver.quit() diff --git a/script/selenium/web_login_open_me_devops_auto.py b/script/selenium/web_login_open_me_devops_auto.py new file mode 100755 index 0000000..23bcf6f --- /dev/null +++ b/script/selenium/web_login_open_me_devops_auto.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import os +import sys + +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.support.ui import WebDriverWait + +private_mode = True +record_mode = False +dark_reader_mode = True + + +def click(driver, xpath, time=5): + wait = WebDriverWait(driver, time) + button = wait.until( + EC.element_to_be_clickable( + ( + By.XPATH, + xpath, + ) + ) + ) + button.click() + + +if record_mode: + new_path = os.path.normpath( + os.path.join(os.path.dirname(__file__), "..", "..") + ) + sys.path.append(new_path) + from script.selenium.selenium_video import VideoRecorder + +# Configuration pour lancer Firefox en mode de navigation privée +firefox_options = webdriver.FirefoxOptions() +if private_mode: + firefox_options.add_argument("--private") + +# Définissez la préférence pour les notifications de bureau +# 1 signifie "autoriser", 2 signifie "bloquer" +firefox_options.set_preference("permissions.default.desktop-notification", 1) + +# Créez une instance du navigateur Firefox avec les options de navigation privée +driver = webdriver.Firefox(options=firefox_options) + +# Ajout de l'enregistrement +if record_mode: + video_recorder = VideoRecorder(driver) +else: + video_recorder = None + +# Install DarkReader to help my eyes +# TODO do a script to check if it's the last version +if dark_reader_mode: + driver.install_addon( + "./script/selenium/darkreader-firefox.xpi", temporary=True + ) + driver.install_addon( + "./script/selenium/odoo_debug-4.0.xpi", temporary=True + ) + +if private_mode and dark_reader_mode: + driver.get("about:addons") + click(driver, "/html/body/div/div[1]/categories-box/button[2]") + click( + driver, + "/html/body/div/div[2]/div/addon-list/section[1]/addon-card/div/div/div/div/button", + ) + click( + driver, + "/html/body/div/div[2]/div/addon-list/section[1]/addon-card/div/addon-options/panel-list/panel-item[5]", + ) + click( + driver, + "/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[5]/div/label[1]/input", + ) + + # Enable Odoo_debug into incognito + # Back + click(driver, "/html/body/div/div[2]/addon-page-header/div/div[2]/button") + click( + driver, + "/html/body/div/div[2]/div/addon-list/section[1]/addon-card[2]/div/div/div/div/button", + ) + click( + driver, + "/html/body/div/div[2]/div/addon-list/section[1]/addon-card[2]/div/addon-options/panel-list/panel-item[5]", + ) + click( + driver, + "/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[5]/div/label[1]/input", + ) + +# Ouvrez la page web +driver.get("http://127.0.0.1:8069/web") + +# Close tab opening by DarkReader +if not private_mode and dark_reader_mode: + driver.switch_to.window(driver.window_handles[-1]) + driver.close() + driver.switch_to.window(driver.window_handles[0]) + +# Démarrer l'enregistrement +if record_mode: + video_recorder.start() + +# Trouvez les éléments du formulaire +courriel_input = driver.find_element(By.NAME, "login") +mot_de_passe_input = driver.find_element(By.NAME, "password") +try: + connexion_button = driver.find_element( + By.XPATH, + "/html/body/div/div/div/form/div[3]/button" + # '//button[contains(text(), "Log in")]' + ) +except Exception: + connexion_button = driver.find_element( + By.XPATH, + "/html/body/div/main/div/form/div[3]/button" + # '//button[contains(text(), "Connexion")]' + ) + +# Remplissez le courriel et le mot de passe +courriel_input.send_keys("admin") +mot_de_passe_input.send_keys("admin") + +# Cliquez sur le bouton "Connexion" +connexion_button.click() + +# Open View +click(driver, "/html/body/header/nav/div/div[1]/div[2]/div/div/div/ul/li[2]/a") +click(driver, "/html/body/div[1]/main/div[2]/div/div/table/tbody/tr[1]/td[2]") +click(driver, "/html/body/header/nav/div/div[1]/div[2]/div/div/div/ul/li[2]/a") +click(driver, "/html/body/div[1]/main/div[2]/div/div/table/tbody/tr[1]/td[2]") + +# CG self +# Bouton modifier +click(driver, "/html/body/div[1]/main/div[1]/div[2]/div/div/div[1]/button[1]") +# Tab CG +click(driver, "/html/body/div[1]/main/div[2]/div/div/div[7]/ul/li[3]/a") +# Disable «Stop Execution if Env Not Clean +# click( +# driver, +# "/html/body/div[1]/main/div[2]/div/div/div[7]/div/div[3]/div[2]/table[2]/tbody/tr/td[1]/label", +# ) +# Gen +click( + driver, + "/html/body/div[1]/main/div[2]/div/div/div[7]/div/div[3]/div[2]/table[1]/tbody/tr[2]/td[1]/button", +) + +# Check error +click(driver, "/html/body/div[1]/main/div[2]/div/div/div[7]/ul/li[14]/a") +# click(driver, "/html/body/div[1]/main/div[2]/div/div/div[6]/div/div[14]/div/div[2]/table/tbody/tr[1]", time=60*2) + +# Arrêter l'enregistrement +if record_mode: + video_recorder.stop() + +# Open conversation chat +# conversation_button = driver.find_element(By.XPATH, '/html/body/header/nav/ul[3]/li[2]/a') +# conversation_button.click() + +# Close bot chat +# conversation_button = driver.find_element(By.XPATH, '/html/body/div[3]/div[1]/span[2]/a[2]') +# conversation_button.click() + +# Fermez le navigateur +# driver.quit() diff --git a/script/selenium/web_login_open_me_devops_auto_force.py b/script/selenium/web_login_open_me_devops_auto_force.py new file mode 100755 index 0000000..8dbb7cd --- /dev/null +++ b/script/selenium/web_login_open_me_devops_auto_force.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import os +import sys + +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.support.ui import WebDriverWait + +private_mode = True +record_mode = False +dark_reader_mode = True + + +def click(driver, xpath, time=5): + wait = WebDriverWait(driver, time) + button = wait.until( + EC.element_to_be_clickable( + ( + By.XPATH, + xpath, + ) + ) + ) + button.click() + + +if record_mode: + new_path = os.path.normpath( + os.path.join(os.path.dirname(__file__), "..", "..") + ) + sys.path.append(new_path) + from script.selenium.selenium_video import VideoRecorder + +# Configuration pour lancer Firefox en mode de navigation privée +firefox_options = webdriver.FirefoxOptions() +if private_mode: + firefox_options.add_argument("--private") + +# Définissez la préférence pour les notifications de bureau +# 1 signifie "autoriser", 2 signifie "bloquer" +firefox_options.set_preference("permissions.default.desktop-notification", 1) + +# Créez une instance du navigateur Firefox avec les options de navigation privée +driver = webdriver.Firefox(options=firefox_options) + +# Ajout de l'enregistrement +if record_mode: + video_recorder = VideoRecorder(driver) +else: + video_recorder = None + +# Install DarkReader to help my eyes +# TODO do a script to check if it's the last version +if dark_reader_mode: + driver.install_addon( + "./script/selenium/darkreader-firefox.xpi", temporary=True + ) + driver.install_addon( + "./script/selenium/odoo_debug-4.0.xpi", temporary=True + ) + +if private_mode and dark_reader_mode: + driver.get("about:addons") + click(driver, "/html/body/div/div[1]/categories-box/button[2]") + click( + driver, + "/html/body/div/div[2]/div/addon-list/section[1]/addon-card/div/div/div/div/button", + ) + click( + driver, + "/html/body/div/div[2]/div/addon-list/section[1]/addon-card/div/addon-options/panel-list/panel-item[5]", + ) + click( + driver, + "/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[5]/div/label[1]/input", + ) + + # Enable Odoo_debug into incognito + # Back + click(driver, "/html/body/div/div[2]/addon-page-header/div/div[2]/button") + click( + driver, + "/html/body/div/div[2]/div/addon-list/section[1]/addon-card[2]/div/div/div/div/button", + ) + click( + driver, + "/html/body/div/div[2]/div/addon-list/section[1]/addon-card[2]/div/addon-options/panel-list/panel-item[5]", + ) + click( + driver, + "/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[5]/div/label[1]/input", + ) + +# Ouvrez la page web +driver.get("http://127.0.0.1:8069/web") + +# Close tab opening by DarkReader +if not private_mode and dark_reader_mode: + driver.switch_to.window(driver.window_handles[-1]) + driver.close() + driver.switch_to.window(driver.window_handles[0]) + +# Démarrer l'enregistrement +if record_mode: + video_recorder.start() + +# Trouvez les éléments du formulaire +courriel_input = driver.find_element(By.NAME, "login") +mot_de_passe_input = driver.find_element(By.NAME, "password") +try: + connexion_button = driver.find_element( + By.XPATH, + "/html/body/div/div/div/form/div[3]/button" + # '//button[contains(text(), "Log in")]' + ) +except Exception: + connexion_button = driver.find_element( + By.XPATH, + "/html/body/div/main/div/form/div[3]/button" + # '//button[contains(text(), "Connexion")]' + ) + +# Remplissez le courriel et le mot de passe +courriel_input.send_keys("admin") +mot_de_passe_input.send_keys("admin") + +# Cliquez sur le bouton "Connexion" +connexion_button.click() + +# Open View +click(driver, "/html/body/header/nav/div/div[1]/div[2]/div/div/div/ul/li[2]/a") +click(driver, "/html/body/div[1]/main/div[2]/div/div/table/tbody/tr[1]/td[2]") +click(driver, "/html/body/header/nav/div/div[1]/div[2]/div/div/div/ul/li[2]/a") +click(driver, "/html/body/div[1]/main/div[2]/div/div/table/tbody/tr[1]/td[2]") + +# CG self +# Bouton modifier +click(driver, "/html/body/div[1]/main/div[1]/div[2]/div/div/div[1]/button[1]") +# Tab CG +click(driver, "/html/body/div[1]/main/div[2]/div/div/div[7]/ul/li[3]/a") +# Disable «Stop Execution if Env Not Clean +click( + driver, + "/html/body/div[1]/main/div[2]/div/div/div[7]/div/div[3]/div[2]/table[2]/tbody/tr/td[1]/label", +) +# Gen +click( + driver, + "/html/body/div[1]/main/div[2]/div/div/div[7]/div/div[3]/div[2]/table[1]/tbody/tr[2]/td[1]/button", +) + +# Check error +click(driver, "/html/body/div[1]/main/div[2]/div/div/div[7]/ul/li[14]/a") +# click(driver, "/html/body/div[1]/main/div[2]/div/div/div[6]/div/div[14]/div/div[2]/table/tbody/tr[1]", time=60*2) + +# Arrêter l'enregistrement +if record_mode: + video_recorder.stop() + +# Open conversation chat +# conversation_button = driver.find_element(By.XPATH, '/html/body/header/nav/ul[3]/li[2]/a') +# conversation_button.click() + +# Close bot chat +# conversation_button = driver.find_element(By.XPATH, '/html/body/div[3]/div[1]/span[2]/a[2]') +# conversation_button.click() + +# Fermez le navigateur +# driver.quit() diff --git a/script/test/run_parallel_test.py b/script/test/run_parallel_test.py index 86dd4cd..a0f2a38 100755 --- a/script/test/run_parallel_test.py +++ b/script/test/run_parallel_test.py @@ -496,9 +496,9 @@ async def test_exec( hook.write(new_hook_line) # Format editing code before commit - await lib_asyncio.run_command_get_output( - "./script/maintenance/black.sh", temp_dir_name - ) + # await lib_asyncio.run_command_get_output( + # "./script/maintenance/format.sh", temp_dir_name + # ) # init repo with git for dir_to_git in lst_path_to_add_config: