Merge branch 'develop'

- Integrate Selenium
- Fix npm installation
- Support osx to open_terminal
- Improve Pycharm script
- Support default configuration Pycharm
- Change format script to reduce test error (but cause others
problems...)
- FAQ error git bind, kill git-daemon
- rename erplibre_workspace/it to erplibre_devops
- upgrade docker version buster to bullseye
This commit is contained in:
Mathieu Benoit 2023-12-02 14:26:30 -05:00
commit 6c66f36be5
36 changed files with 1124 additions and 244 deletions

20
.editorconfig Normal file
View file

@ -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

2
.gitignore vendored
View file

@ -24,3 +24,5 @@ get-poetry.py
artifacts artifacts
wkhtmltox* wkhtmltox*
cache cache
node_modules

View file

@ -7,6 +7,23 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] ## [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 ## [1.5.0] - 2023-07-07
**Migration note** **Migration note**

View file

@ -1,27 +1,31 @@
name,script_path,parameters,folder name,script_path,parameters,folder,default
run,./odoo/odoo-bin,--limit-time-real 999999 -c config.conf,run run,./odoo/odoo-bin,--limit-time-real 999999 -c config.conf,run,True
run_parallel_test,./script/test/run_parallel_test.py,,test 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,./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 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_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,./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_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,./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_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,./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_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_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_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_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_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_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_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_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,./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_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_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_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_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_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 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 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,

1 name script_path parameters folder default
2 run ./odoo/odoo-bin --limit-time-real 999999 -c config.conf run True
3 run_parallel_test ./script/test/run_parallel_test.py test
4 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
5 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
6 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
7 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
8 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
9 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
10 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
11 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
12 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
13 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
14 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
15 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
16 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
17 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
18 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
19 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
20 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
21 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
22 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
23 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
24 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
25 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
26 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
27 create demo internal ./script/code_generator/new_project.py -m demo_internal -d addons/TechnoLibre_odoo-code-generator-template new cg project
28 run_robotlibre ./odoo/odoo-bin --limit-time-real 999999 -c config.conf -d robotlibre robotlibre
29 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
30 run_robotlibre_generate ./script/code_generator/new_project.py -f -d ./addons/ERPLibre_erplibre_addons -m erplibre_devops robotlibre
31

View file

@ -10,3 +10,4 @@ doc/odoo_documentation-user
artifacts artifacts
cache cache
htmlcov htmlcov
node_modules

View file

@ -85,6 +85,14 @@ git rebase -i HEAD~4 -x "git commit --amend --author 'Author Name <author.name@m
git cherry-pick -m 1 --strategy-option theirs HASH git cherry-pick -m 1 --strategy-option theirs HASH
``` ```
## git update manifest
### Error fatal: unable to allocate any listen sockets on port 9418
```bash
pkill git-daemon
```
## git-repo ## git-repo
### error.GitError fatal bad revision ### error.GitError fatal bad revision

View file

@ -98,10 +98,14 @@ cd /[EL_USER]/erplibre
## Move prod database to dev ## Move prod database to dev
When moving prod database to your dev environment, you want to remove email servers and install user test to test the When moving prod database to your dev environment, you want to remove email servers and install user test to test the
database. WARNING, this is not safe for production, you will expose all data. Run: database. WARNING, this is not safe for production, you will expose all data.
1. Copy your database image to directory image_db, exemple the image name is `my_db.zip`
1. Run
```bash ```bash
./script/database/migrate_prod_to_test.sh DATABASE ./script/database/db_restore.py --clean_cache --database test_my_db --image my_db
./script/addons/update_prod_to_dev.sh test_my_db
``` ```
## Update production ## Update production

View file

@ -1,4 +1,4 @@
FROM python:3.7.16-slim-buster FROM python:3.7.17-slim-bullseye
MAINTAINER TechnoLibre <docker@technolibre.ca> MAINTAINER TechnoLibre <docker@technolibre.ca>
SHELL ["/bin/bash", "-xo", "pipefail", "-c"] SHELL ["/bin/bash", "-xo", "pipefail", "-c"]
@ -27,6 +27,10 @@ RUN apt-get update \
npm \ npm \
xz-utils \ xz-utils \
git \ git \
tree \
vim \
htop \
tig \
wget \ wget \
make \ make \
libssl-dev \ libssl-dev \
@ -56,8 +60,8 @@ RUN apt-get update \
libncursesw5-dev \ libncursesw5-dev \
libffi-dev \ libffi-dev \
uuid-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 \ && 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 '7e35a63f9db14f93ec7feeb0fce76b30c08f2057 wkhtmltox.deb' | sha1sum -c - \ && echo 'd9f259a67e05e1c221d48b504453645e6c491fab wkhtmltox.deb' | sha1sum -c - \
&& apt-get install -y --no-install-recommends ./wkhtmltox.deb \ && apt-get install -y --no-install-recommends ./wkhtmltox.deb \
&& rm -rf /var/lib/apt/lists/* wkhtmltox.deb && rm -rf /var/lib/apt/lists/* wkhtmltox.deb

View file

@ -43,6 +43,10 @@ RUN cd $ODOO_PREFIX && \
./.venv/bin/poetry --version && \ ./.venv/bin/poetry --version && \
./.venv/bin/poetry install ./.venv/bin/poetry install
# Install local npm
RUN cd $ODOO_PREFIX && \
npm install
RUN cd $ODOO_PREFIX && \ RUN cd $ODOO_PREFIX && \
head /etc/odoo/odoo.conf && \ head /etc/odoo/odoo.conf && \
./docker/repo_manifest_gen_org_prefix_path.py $ODOO_PREFIX/addons /etc/odoo/odoo.conf /etc/odoo/odoo.conf && \ ./docker/repo_manifest_gen_org_prefix_path.py $ODOO_PREFIX/addons /etc/odoo/odoo.conf /etc/odoo/odoo.conf && \

66
package-lock.json generated Normal file
View file

@ -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
}
}
}

11
package.json Normal file
View file

@ -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"
}
}

View file

@ -49,7 +49,17 @@ cd "$3" || exit 1
git checkout -- "*.po*" git checkout -- "*.po*"
cd - || exit 1 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}" echo "TEST ${2}"
./script/code_generator/check_git_change_code_generator.sh "$3" ./script/code_generator/check_git_change_code_generator.sh "$3"
retVal=$? retVal=$?

View file

@ -57,6 +57,11 @@ def get_config():
required=True, required=True,
help="Module name to create", help="Module name to create",
) )
parser.add_argument(
"--odoo_config",
default="./config.conf",
help="Odoo config path",
)
parser.add_argument( parser.add_argument(
"--config", "--config",
help="""Configuration to create models with fields and type. JSON style. help="""Configuration to create models with fields and type. JSON style.
@ -116,12 +121,14 @@ class ProjectManagement:
keep_bd_alive=False, keep_bd_alive=False,
coverage=False, coverage=False,
config="", config="",
odoo_config="./config.conf",
): ):
self.force = force self.force = force
self._coverage = coverage self._coverage = coverage
self.keep_bd_alive = keep_bd_alive self.keep_bd_alive = keep_bd_alive
self.msg_error = "" self.msg_error = ""
self.has_config_update = False self.has_config_update = False
self.odoo_config = odoo_config
self.module_directory = module_directory self.module_directory = module_directory
if not os.path.exists(self.module_directory): if not os.path.exists(self.module_directory):
@ -522,7 +529,7 @@ class ProjectManagement:
os.system(cmd) os.system(cmd)
# Validate # Validate
if not os.path.exists(template_path): if not os.path.exists(module_path):
_logger.error(f"Module not exists '{module_path}'") _logger.error(f"Module not exists '{module_path}'")
return False return False
else: else:
@ -532,7 +539,7 @@ class ProjectManagement:
def update_config(self): def update_config(self):
config = configparser.ConfigParser() config = configparser.ConfigParser()
config.read("./config.conf") config.read(self.odoo_config)
addons_path = config.get("options", "addons_path") addons_path = config.get("options", "addons_path")
lst_addons_path = addons_path.split(",") lst_addons_path = addons_path.split(",")
lst_directory = list( lst_directory = list(
@ -579,6 +586,7 @@ def main():
keep_bd_alive=config.keep_bd_alive, keep_bd_alive=config.keep_bd_alive,
coverage=config.coverage, coverage=config.coverage,
config=config.config, config=config.config,
odoo_config=config.odoo_config,
) )
if project.msg_error: if project.msg_error:
return -1 return -1

View file

@ -212,8 +212,8 @@ def main():
with open(hooks_file_path, "w") as source: with open(hooks_file_path, "w") as source:
source.write(new_file_content) source.write(new_file_content)
# Call black # Call format all file
os.system(f"./script/maintenance/black.sh {hooks_file_path}") os.system(f"./script/maintenance/format.sh {hooks_file_path}")
return 0 return 0

View file

@ -65,10 +65,22 @@ def get_config():
action="store_true", action="store_true",
help="Initialize minimum configuration for Pycharm.", help="Initialize minimum configuration for Pycharm.",
) )
parser.add_argument(
"--overwrite",
action="store_true",
help="Remove old data and replace it.",
)
args = parser.parse_args() 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 args.configuration = True
if args.overwrite:
args.init = True
else: else:
args.configuration = False args.configuration = False
@ -78,6 +90,7 @@ def get_config():
def main(): def main():
has_execute = False has_execute = False
config = get_config() config = get_config()
_logger.info(f"Work on directory {os.getcwd()}")
# TODO modifier vcs.xml pour le mapping des répertoires git # 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): 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: with open(file_name) as xml:
xml_as_string = xml.read() xml_as_string = xml.read()
dct_project_xml = xmltodict.parse(xml_as_string) 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) xml.write(xml_format)
_logger.info(f"File {file_name} has been write.") _logger.info(f"File {file_name} has been write.")
subprocess.call( subprocess.call(
"prettier --tab-width 2 --print-width 999999 --write" f"script/maintenance/prettier_xml.sh '{file_name}'",
f" '{file_name}'",
shell=True, shell=True,
) )
else: else:
@ -150,6 +163,28 @@ def add_configuration(dct_xml, file_name, config):
not bool(lst_component), not bool(lst_component),
f"Missing 'project/component' into {file_name}", 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 = [ dct_component = [
a for a in lst_component if a.get("@name") == "RunManager" 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 # Create it
dct_component = { dct_component = {
"@name": "RunManager", "@name": "RunManager",
"@selected": "Python.pycharm_configuration", # "@selected": "Python.pycharm_configuration",
"recent_temporary": { # "recent_temporary": {
"list": { # "list": {
"item": {"@itemvalue": "Python.pycharm_configuration"} # "item": {"@itemvalue": "Python.pycharm_configuration"}
} # }
}, # },
"configuration": [], "configuration": [],
"list": {"item": []}, "list": {"item": []},
} }
@ -219,116 +254,124 @@ def add_configuration(dct_xml, file_name, config):
for conf in lst_configuration: for conf in lst_configuration:
print(f"\t{conf}") print(f"\t{conf}")
if config.init: last_default = None
if os.path.isfile(PATH_DEFAULT_CONFIGURATION): if not config.init:
with open(PATH_DEFAULT_CONFIGURATION) as txt: return has_change
for default_conf in csv.DictReader(txt): if not os.path.isfile(PATH_DEFAULT_CONFIGURATION):
conf_name = default_conf.get("name") _logger.error(f"Cannot read file '{PATH_DEFAULT_CONFIGURATION}'")
conf_folder = default_conf.get("folder") return has_change
conf_script_path = default_conf.get("script_path") with open(PATH_DEFAULT_CONFIGURATION) as txt:
conf_script_path_replace = ( for default_conf in csv.DictReader(txt):
conf_script_path conf_name = default_conf.get("name")
if not conf_script_path.startswith("./") conf_folder = default_conf.get("folder")
else f"$PROJECT_DIR${conf_script_path[1:]}" 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") else:
s_unique_key = ( has_change = True
f"d {conf_folder} s" lst_xml_configuration_name.append(
f" {conf_script_path} p" {"@itemvalue": f"Python.{conf_name}"}
f" {conf_parameter}"
) )
if s_unique_key not in lst_unique_configuration: conf_full = {
# add it! "@name": conf_name,
if conf_name in lst_configuration: "@type": "PythonConfigurationType",
_logger.error( "@factoryName": "Python",
f"Cannot add configuration name '{conf_name}'," "module": {"@name": PROJECT_NAME},
" already exist. Delete it manually." "option": [
) {
else: "@name": "INTERPRETER_OPTIONS",
has_change = True "@value": "",
lst_xml_configuration_name.append( },
{"@itemvalue": f"Python.conf_name"} {"@name": "PARENT_ENVS", "@value": "true"},
) {
conf_full = { "@name": "SDK_HOME",
"@name": conf_name, "@value": "$PROJECT_DIR$/.venv/bin/python",
"@type": "PythonConfigurationType", },
"@factoryName": "Python", {
"module": {"@name": PROJECT_NAME}, "@name": "WORKING_DIRECTORY",
"option": [ "@value": "$PROJECT_DIR$",
{ },
"@name": "INTERPRETER_OPTIONS", {
"@value": "", "@name": "IS_MODULE_SDK",
}, "@value": "false",
{"@name": "PARENT_ENVS", "@value": "true"}, },
{ {
"@name": "SDK_HOME", "@name": "ADD_CONTENT_ROOTS",
"@value": ( "@value": "true",
"$PROJECT_DIR$/.venv/bin/python" },
), {
}, "@name": "ADD_SOURCE_ROOTS",
{ "@value": "true",
"@name": "WORKING_DIRECTORY", },
"@value": "$PROJECT_DIR$", {
}, "@name": "SCRIPT_NAME",
{ "@value": conf_script_path_replace,
"@name": "IS_MODULE_SDK", },
"@value": "false", {
}, "@name": "PARAMETERS",
{ "@value": conf_parameter,
"@name": "ADD_CONTENT_ROOTS", },
"@value": "true", {
}, "@name": "SHOW_COMMAND_LINE",
{ "@value": "false",
"@name": "ADD_SOURCE_ROOTS", },
"@value": "true", {
}, "@name": "EMULATE_TERMINAL",
{ "@value": "false",
"@name": "SCRIPT_NAME", },
"@value": conf_script_path_replace, {
}, "@name": "MODULE_MODE",
{ "@value": "false",
"@name": "PARAMETERS", },
"@value": conf_parameter, {
}, "@name": "REDIRECT_INPUT",
{ "@value": "false",
"@name": "SHOW_COMMAND_LINE", },
"@value": "false", {"@name": "INPUT_FILE", "@value": ""},
}, ],
{ "envs": {
"@name": "EMULATE_TERMINAL", "env": {
"@value": "false", "@name": "PYTHONUNBUFFERED",
}, "@value": "1",
{
"@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"},
} }
if conf_folder: },
conf_full["@folderName"] = conf_folder "EXTENSION": {
lst_configuration_full.insert(0, conf_full) "@ID": "PythonCoverageRunConfigurationExtension",
else: "@runner": "coverage.py",
_logger.info( },
f"Configuration already exist: '{s_unique_key}'" "method": {"@v": "2"},
) }
else: if conf_folder:
_logger.error(f"Cannot read file '{PATH_DEFAULT_CONFIGURATION}'") 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 return has_change

View file

@ -35,8 +35,7 @@ echo "\n---- Installing nodeJS NPM and rtlcss for LTR support ----"
brew install nodejs npm openssl brew install nodejs npm openssl
sudo npm install -g rtlcss sudo npm install -g rtlcss
sudo npm install -g less sudo npm install -g less
sudo npm install -g prettier npm install
sudo npm install -g prettier @prettier/plugin-xml
echo 'export PATH="/usr/local/opt/openssl@1.1/bin:$PATH"' >> ~/.zshrc echo 'export PATH="/usr/local/opt/openssl@1.1/bin:$PATH"' >> ~/.zshrc

View file

@ -89,74 +89,46 @@ if [[ $retVal -ne 0 ]]; then
fi fi
echo -e "\n---- Installing nodeJS NPM and rtlcss for LTR support ----" 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 if [ "18.04" == "${UBUNTU_VERSION}" ]; then
sudo apt remove nodeJS npm sudo apt remove nodeJS npm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.2/install.sh | bash NODE_MAJOR=16
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
else else
curl -fsSL https://deb.nodesource.com/setup_current.x | sudo -E bash - NODE_MAJOR=20
sudo apt-get install -y nodejs fi
retVal=$?
if [[ $retVal -ne 0 ]]; then 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
echo "apt-get nodejs installation error." sudo apt-get update
exit 1 sudo apt-get install nodejs -y
fi
sudo npm install npm@latest -g sudo npm install npm@latest -g
retVal=$? retVal=$?
if [[ $retVal -ne 0 ]]; then if [[ $retVal -ne 0 ]]; then
echo "npm install npm lastest installation error." echo "npm install npm lastest installation error."
exit 1 exit 1
fi fi
sudo npm install -g rtlcss sudo npm install -g rtlcss
retVal=$? retVal=$?
if [[ $retVal -ne 0 ]]; then if [[ $retVal -ne 0 ]]; then
echo "npm install rtlcss installation error." echo "npm install rtlcss installation error."
exit 1 exit 1
fi fi
sudo npm install -g less sudo npm install -g less
retVal=$? retVal=$?
if [[ $retVal -ne 0 ]]; then if [[ $retVal -ne 0 ]]; then
echo "npm install less installation error." echo "npm install less installation error."
exit 1 exit 1
fi
fi fi
echo -e "\n---- Test tool ----" echo -e "\n---- Test tool ----"
sudo npm install -g prettier npm install
retVal=$? retVal=$?
if [[ $retVal -ne 0 ]]; then if [[ $retVal -ne 0 ]]; then
echo "npm install prettier installation error." echo "npm install prettier + plugin-xml 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."
exit 1 exit 1
fi fi

View file

@ -75,6 +75,7 @@ if [[ ! -d ${VENV_PATH} ]]; then
exit 1 exit 1
fi fi
fi fi
source ./.venv/bin/activate
#if [[ ! -d "${POETRY_PATH}" ]]; then #if [[ ! -d "${POETRY_PATH}" ]]; then
# # Delete directory ~/.poetry and .venv to force update to new version # # Delete directory ~/.poetry and .venv to force update to new version

View file

@ -17,6 +17,8 @@ if [[ $retVal -ne 0 ]]; then
exit 1 exit 1
fi fi
npm install
## Install maintainer-tools ## Install maintainer-tools
#cd script/OCA_maintainer-tools || exit #cd script/OCA_maintainer-tools || exit
## virtualenv is not installed by default ## virtualenv is not installed by default

View file

@ -2,7 +2,7 @@
# This will format all python file # This will format all python file
# argument 1: directory or file to format # argument 1: directory or file to format
source ./.venv/bin/activate source ./.venv/bin/activate
black -l 79 --preview -t py37 $@ black -l 79 --preview -t py37 "$@"
retVal=$? retVal=$?
if [[ $retVal -ne 0 ]]; then if [[ $retVal -ne 0 ]]; then
echo "Error black format" echo "Error black format"

8
script/maintenance/format.sh Executable file
View file

@ -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"

View file

@ -1,3 +1,5 @@
#!/usr/bin/env bash #!/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 "$@" ./script/maintenance/black.sh "$@"

View file

@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# This will format all js,css,html # This will format all js,css,html
# argument 1: directory or file to format # argument 1: directory or file to format
prettier --write $@ ./node_modules/.bin/prettier --tab-width 4 --print-width 120 --no-bracket-spacing --write "$@"
retVal=$? retVal=$?
if [[ $retVal -ne 0 ]]; then if [[ $retVal -ne 0 ]]; then
echo "Error prettier format" echo "Error prettier format"

View file

@ -4,14 +4,14 @@
STR_ARG="'$*'" STR_ARG="'$*'"
if [[ "${STR_ARG}" = *"/data/"* ]]; then if [[ "${STR_ARG}" = *"/data/"* ]]; then
# Need to keep width with data, else add corrupted string data # 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 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 # 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 $@ #prettier --xml-whitespace-sensitivity "strict" --prose-wrap always --tab-width 4 --no-bracket-spacing --print-width 120 --write $@
fi fi
retVal=$? retVal=$?
if [[ $retVal -ne 0 ]]; then if [[ $retVal -ne 0 ]]; then
echo "Error prettier format" echo "Error prettier-xml format"
exit 1 exit 1
fi fi

View file

@ -8,7 +8,7 @@
git daemon --base-path=. --export-all --reuseaddr --informative-errors --verbose & git daemon --base-path=. --export-all --reuseaddr --informative-errors --verbose &
DAEMON_PID=$! 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} ./.venv/repo sync -v --force-sync -m ${EL_MANIFEST_DEV}
kill ${DAEMON_PID} kill ${DAEMON_PID}

View file

@ -1,26 +1,47 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Open a new gnome-terminal with different path on new tab # Open a new gnome-terminal with different path on new tab
working_path=`readlink -f .` working_path=$(readlink -f .)
paths=( paths=(
"${working_path}/" "${working_path}/"
"${working_path}/addons/TechnoLibre_odoo-code-generator" # "${working_path}/addons/TechnoLibre_odoo-code-generator"
"${working_path}/addons/TechnoLibre_odoo-code-generator-template" # "${working_path}/addons/TechnoLibre_odoo-code-generator-template"
"${working_path}/addons/ERPLibre_erplibre_addons" "${working_path}/addons/ERPLibre_erplibre_addons"
"${working_path}/addons/OCA_server-tools" # "${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="" first_iteration=true
for t in "${paths[@]}"; do if [[ "${OSTYPE}" == "linux-gnu" ]]; then
LONGCMD+=${cmd_before}${t}${cmd_after} cmd_before="cd "
done 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 # Boucle pour ajouter des commandes pour ouvrir de nouveaux onglets et exécuter les scripts batch
#echo "gnome-terminal --window -- bash -c \"${LONGCMD}\"" for t in "${paths[@]}"; do
gnome-terminal --window -- bash -c "${LONGCMD}" 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

View file

Binary file not shown.

View file

@ -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

Binary file not shown.

View file

@ -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

44
script/selenium/web_login.py Executable file
View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -496,9 +496,9 @@ async def test_exec(
hook.write(new_hook_line) hook.write(new_hook_line)
# Format editing code before commit # Format editing code before commit
await lib_asyncio.run_command_get_output( # await lib_asyncio.run_command_get_output(
"./script/maintenance/black.sh", temp_dir_name # "./script/maintenance/format.sh", temp_dir_name
) # )
# init repo with git # init repo with git
for dir_to_git in lst_path_to_add_config: for dir_to_git in lst_path_to_add_config: