Compare commits

...

79 Commits
1.0.2 ... main

Author SHA1 Message Date
94a718457b feat: add configurable env_file parameter to git_aggregate function
- Add optional env_file parameter with default value ".env"
- Convert relative env_file paths to absolute paths before directory change
- Maintain backward compatibility with existing calls
- Improve flexibility for different environment file locations
2025-10-04 13:24:49 +02:00
a5f7f2e88c merge 1.3.1 2025-10-03 20:52:24 +02:00
bf07bc1865 [FIX] cli.py: comment import debugypy 2025-06-02 07:40:08 +02:00
e41abfc928 revert pyproject.toml 2025-06-01 15:28:30 +02:00
a34d880721 added option custom_addon in config.yaml 2025-05-27 07:52:50 +02:00
a362783e6d odoo_openupgrade_wizard/tools/tools_system.py aktualisiert 2025-05-19 20:57:08 +02:00
Rémy Taymans
6bb379d92b [VER] Bump to version 1.3.0 2025-05-04 16:16:24 +02:00
Rémy Taymans
e8da97fca7 [IMP] release documentation 2025-05-04 16:05:56 +02:00
Rémy Taymans
7b8f9f828a Merge branch '16.0-add-postgres-default-database' into 'main'
[IMP] cli tools: default 'postgres' database.

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!112
2025-05-04 13:16:51 +00:00
Rémy Taymans
3c5a589cd8 Merge branch 'disable_odoo_memory_limit' into 'main'
disable odoo memory limit

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!114
2025-05-04 13:14:22 +00:00
hugues de keyzer
32cde3f0e7 disable odoo memory limit by default
by default, odoo limits the available memory to 2560 MiB, which can
cause MemoryError exceptions, especially when dealing with high amounts
of records. disable this limit by default.
2025-05-02 16:37:29 +02:00
LE GAL SYLVAIN
2e2799c612 Merge branch 'bump-version-1.2.0' into 'main'
[VER] Bump to version 1.2.0

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!113
2025-04-12 15:09:23 +00:00
Sylvain LE GAL
43370fae23 [VER] Bump to version 1.2.0 2025-04-12 15:39:22 +02:00
Sylvain LE GAL
8bf6dd385a [IMP] cli tools: default 'postgres' database.
Rational: when calling oow psql, sometimes, we don't want to put a database. Example, if we call "oow -d postgres -c 'psql'".
In that case, this improvment makes that default postgres database will be proposed in the 'prompt', if no database is provided
2025-02-27 12:45:16 +01:00
Rémy Taymans
42bf4f4379 Merge branch 'add-option-skip-update-all' into 'main'
[IMP] oow upgrade. Add skip_update as an option in config.yml.

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!111
2025-02-11 13:41:47 +00:00
Sylvain LE GAL
bfde1ddc1f fixup! [IMP] oow upgrade. Add skip_update as an option in config.yml. (migration_step option). If enabled, in this step, the update all will be skipped, and only pre-migration (SQL) and post-migration (python script) will be executed. This is interesting: - for the first step, if your production is up-to-date, to save time. - for the last step, in recent version (since V14), where openupgrade doesn't contain odoo code. In that case, you should be sure that all your migration is OK, because in openupgrade context, some errors are just ignored. Use this option with caution. 2025-02-11 10:45:25 +01:00
Rémy Taymans
9687e8656a Merge branch 'imp-restoredb' into 'main'
[IMP] cli restoredb: manage filstore in subfolder

Closes #63

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!109
2025-02-03 15:18:04 +00:00
Rémy Taymans
65e7e2c57e [FIX] newsfragments 2025-02-03 15:56:00 +01:00
Sylvain LE GAL
4fc7056932 [IMP] oow upgrade. Add skip_update as an option in config.yml. (migration_step option). If enabled, in this step, the update all will be skipped, and only pre-migration (SQL) and post-migration (python script) will be executed.
This is interesting:
- for the first step, if your production is up-to-date, to save time.
- for the last step, in recent version (since V14), where openupgrade doesn't contain odoo code. In that case, you should be sure that all your migration is OK, because in openupgrade context, some errors are just ignored.
Use this option with caution.
2025-02-03 11:26:37 +01:00
Simon Maillard
ca53f46248 [IMP] Use builtins "exists" click feature to check if provided files
exists
2025-02-01 13:59:11 +00:00
Simon Maillard
7d1183b140 [IMP] cli restoredb: manage filestore in subfolder 2025-01-31 19:28:01 +00:00
Rémy Taymans
a00ee58b62 Merge branch 'IMP-estimate-workload-hide-done-work' into 'main'
[IMP] estimate-workload html file

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!110
2025-01-31 15:28:30 +00:00
Rémy Taymans
2abf4ee896 [ADD] Newsfragments 2025-01-31 16:06:00 +01:00
Sylvain LE GAL
c66789dc71 [FIX] template: correct indentation 2025-01-31 15:24:40 +01:00
Rémy Taymans
026cae6f5e Merge branch 'split_generate_odoo_command' into 'main'
[IMP] split generate_odoo_command

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!104
2025-01-31 12:45:14 +00:00
Rémy Taymans
a960ddc83c [ADD] newsfragments 2025-01-31 13:23:38 +01:00
Rémy Taymans
95f58f3a9f [FIX] generate_odoo_command_options docstring 2025-01-31 13:23:38 +01:00
Simon Maillard
d595c6584c [IMP] split generate_odoo_command
In 2 functions:

-  generate_odoo_command_options
-  generate_odoo_command

To be able to use generate_odoo_command_options from other places
2025-01-31 13:23:38 +01:00
Rémy Taymans
eec7068628 Merge branch 'update-poetry' into 'main'
[UPD] update to poetry 2.0.0

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!108
2025-01-09 11:16:20 +00:00
Rémy Taymans
a3015e579a [UPD] update to poetry 2.0.0 2025-01-09 10:45:32 +01:00
LE GAL SYLVAIN
8003a86bc1 Merge branch 'fix-readme' into 'main'
[FIX] missing shell command and typos in README.md

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!106
2025-01-07 21:00:06 +00:00
Sergio Zanchetta
c4f0214cc7 [FIX] missing shell command and typos in README.md 2025-01-07 21:32:45 +01:00
Rémy Taymans
f965f867ec Merge branch 'bump-version-1.1.0' into 'main'
Bump to version 1.1.0

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!103
2024-11-07 10:12:32 +00:00
Rémy Taymans
6c069dbffd [VER] Bump to version 1.1.0 2024-11-07 10:48:43 +01:00
Rémy Taymans
188744be2e [FIX] newsfragments 2024-11-07 10:47:18 +01:00
LE GAL SYLVAIN
88b2789f9b Merge branch 'ADD-guess-dependencies' into 'main'
[ADD] guess requirements feature

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!92
2024-11-06 13:29:17 +00:00
Rémy Taymans
86b59fe127 Merge branch 'save-planet-python3-12--3-13' into 'main'
[REM] remove compatibility with python3.9 / python3.10 / python3.11. Keep only 3.12 and 3.13

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!101
2024-11-06 13:08:02 +00:00
Sylvain LE GAL
429a1da9b1 [REM] Test only on the first and the last supported python version. (python3.9 and python3.13.
This change allow to save time and resources on CI execution.
2024-11-05 17:30:21 +01:00
LE GAL SYLVAIN
4a44369d84 Merge branch 'FIX-MR-98' into 'main'
[FIX] move fragment in the correct place

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!102
2024-11-05 16:07:31 +00:00
Sylvain LE GAL
09347959fe [FIX] move fragment in the correct place 2024-11-05 15:15:04 +01:00
Sylvain LE GAL
4b4ec890b2 fixup! fixup! fixup! [ADD] guess requirements feature 2024-11-05 15:03:13 +01:00
Sylvain LE GAL
5178bbc8ff fixup! fixup! [ADD] guess requirements feature 2024-11-05 13:44:09 +01:00
Sylvain LE GAL
0bfacbd133 fixup! [ADD] guess requirements feature 2024-11-05 01:00:52 +01:00
Sylvain LE GAL
68bfe19acd [REF] simplify code 2024-11-04 20:42:07 +01:00
Sylvain LE GAL
3b3d652756 [ADD] guess requirements feature 2024-11-04 20:42:07 +01:00
LE GAL SYLVAIN
8791a883f9 Merge branch 'ADD-17.0-branch' into 'main'
[ADD] Support 17.0

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!100
2024-11-04 13:06:16 +00:00
Sylvain LE GAL
2d4a7d6917 [FIX] remove docker build warning, regarding ENV values.
WARN: LegacyKeyValueFormat: 'ENV key=value' should be used instead of legacy 'ENV key value' format
2024-11-04 11:32:53 +01:00
Sylvain LE GAL
c0b8be6b20 [ADD] support 18.0 2024-11-04 11:26:23 +01:00
Sylvain LE GAL
1f079e088e [ADD] support 17.0 2024-11-04 11:22:37 +01:00
Sylvain LE GAL
0785c31825 [REF] Improve settings. Introduce _FIRST_ODOO_VERSION_SUPPORTED and _LAST_ODOO_VERSION_SUPPORTED 2024-11-04 10:55:46 +01:00
LE GAL SYLVAIN
684b1b1d3e Merge branch 'FIX-raise-error' into 'main'
[FIX] raise error when building a docker image

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!99
2024-11-03 23:12:40 +00:00
Sylvain LE GAL
1b201a52d4 [FIX] raise error. 2024-11-02 14:44:23 +01:00
LE GAL SYLVAIN
02cf5f2d51 Merge branch 'python3.13' into 'main'
[ADD] compatibility with python3.13

Closes #62

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!98
2024-10-29 14:40:17 +00:00
Sylvain LE GAL
4bf0a1c055 [ADD] fragment 2024-10-29 13:55:06 +01:00
Sylvain LE GAL
f500cbc6aa [REF] poetry update 2024-10-29 13:53:32 +01:00
Sylvain LE GAL
ab513187f5 [ADD] compatibility with python3.13 2024-10-29 13:38:08 +01:00
Rémy Taymans
ea925e2a17 Merge branch 'bump-version-1.0.3' into 'main'
[VER] Bump to version 1.0.3

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!97
2024-10-10 08:12:52 +00:00
Rémy Taymans
f8dea5022a [VER] Bump to version 1.0.3 2024-10-09 21:34:32 +02:00
Rémy Taymans
02a22a80f7 [FIX] newsfragments 2024-10-09 15:45:30 +02:00
Rémy Taymans
3159d61b8c Merge branch 'fix_psycopg2_and_pg_auth_method_conflict' into 'main'
[FIX] psycopg2 / pg versions auth conflict

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!83
2024-10-09 13:40:18 +00:00
Sylvain LE GAL
e77b99ea82 [ADD] fragment to describe odoo 12 / Postgreqsl 14 Bug Fix 2024-10-09 14:50:59 +02:00
Simon Maillard
f0bc155c3b [FIX] psycopg2 / pg versions auth conflict
Downgrade auth method/encryption to md5 if initial odoo version is <=12
and postgres version >=14
2024-10-09 14:50:59 +02:00
Rémy Taymans
ce28b99600 [ADD] build-error bugfix newsfragments 2024-10-09 14:48:00 +02:00
Rémy Taymans
5ddbbc39e2 Merge branch 'fix-docker-build-handling' into 'main'
[FIX] Docker build failure doesn't display logs because build_log is now a list of dicts?

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!89
2024-10-09 12:46:36 +00:00
Rémy Taymans
477164e68a [ADD] newsfragments 2024-10-08 16:55:14 +02:00
Rémy Taymans
fbb4732fa2 [FIX] newsfragments 2024-10-08 16:14:11 +02:00
Rémy Taymans
6b7f1d008f Merge branch 'fix-60-second-try-container-already-in-progress' into 'main'
[Fix]  container already in progress (second try)

Closes #60

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!94
2024-10-08 14:00:17 +00:00
Sylvain LE GAL
1d15b1f8d3 [FIX] Try to #60. introduce retry mechanism when container removal failed 2024-10-08 15:16:06 +02:00
LE GAL SYLVAIN
5b49b2028f Merge branch 'imp-dev-doc' into 'main'
[DOC] explain newsfragments usage in dev doc

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!96
2024-10-08 13:11:12 +00:00
Rémy Taymans
91c4e0804d [FIX] newsfragments extension 2024-10-08 14:44:30 +02:00
Rémy Taymans
1417df2315 [DOC] explain newsfragments usage in dev doc 2024-10-08 14:44:04 +02:00
Rémy Taymans
c5c7c24ee6 Merge branch 'log_container_status_for_debug' into 'main'
[DBG] temporary add debug statement

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!95
2024-10-08 12:32:51 +00:00
Simon Maillard
eb22c93e15 [DBG] temporary add debug statement 2024-10-08 11:40:02 +02:00
Rémy Taymans
d5c9919139 Merge branch 'readme-highlight' into 'main'
[DOC] hightlight code

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!93
2024-10-08 09:24:12 +00:00
Sylvain LE GAL
2aefc0da6f [DOC] hightlight code 2024-10-08 01:28:30 +02:00
Rémy Taymans
4c244fa445 Merge branch 'poetry-update-2024-10-07' into 'main'
[REF] Update python libraries, using poetry update. Details:

See merge request odoo-openupgrade-wizard/odoo-openupgrade-wizard!91
2024-10-07 13:01:14 +00:00
Sylvain LE GAL
f5ba815607 [ADD] fragment 2024-10-07 14:07:33 +02:00
Sylvain LE GAL
d9e8824b04 [REF] Update python libraries, using poetry update. Details:
Package operations: 0 installs, 27 updates, 1 removal

  • Removing incremental (22.10.0)
  • Updating attrs (23.2.0 -> 24.2.0)
  • Updating certifi (2024.2.2 -> 2024.8.30)
  • Updating filelock (3.13.2 -> 3.16.1)
  • Updating idna (3.6 -> 3.10)
  • Updating packaging (24.0 -> 24.1)
  • Updating platformdirs (4.2.0 -> 4.3.6)
  • Updating pygments (2.17.2 -> 2.18.0)
  • Updating pyyaml (6.0.1 -> 6.0.2)
  • Updating tomli (2.0.1 -> 2.0.2)
  • Updating typing-extensions (4.10.0 -> 4.12.2)
  • Updating urllib3 (2.2.1 -> 2.2.3)
  • Updating zipp (3.18.1 -> 3.20.2)
  • Updating argcomplete (3.2.3 -> 3.5.1)
  • Updating astroid (3.1.0 -> 3.3.5)
  • Updating coverage (7.4.4 -> 7.6.1)
  • Updating dill (0.3.8 -> 0.3.9)
  • Updating gitpython (3.1.42 -> 3.1.43)
  • Updating jinja2 (3.1.3 -> 3.1.4)
  • Updating requests (2.31.0 -> 2.32.3)
  • Updating rich (13.7.1 -> 13.9.2)
  • Updating setuptools (69.2.0 -> 75.1.0)
  • Updating tomlkit (0.12.4 -> 0.13.2)
  • Updating virtualenv (20.25.1 -> 20.26.6)
  • Updating docker (7.0.0 -> 7.1.0)
  • Updating plumbum (1.8.2 -> 1.9.0)
  • Updating pylint (3.1.0 -> 3.3.1)
  • Updating towncrier (23.11.0 -> 24.8.0)
2024-10-07 11:00:17 +02:00
Alexandre Aubin
99b710a703 [FIX] Docker build failure doesn't display logs because build_log is now a list of dicts? 2024-10-03 20:04:13 +02:00
59 changed files with 2688 additions and 1061 deletions

View File

@ -77,9 +77,7 @@ pytest:
matrix:
- PYTHON_VERSION:
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3.13"
build:
stage: build

23
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,23 @@
{
// Verwendet IntelliSense zum Ermitteln möglicher Attribute.
// Zeigen Sie auf vorhandene Attribute, um die zugehörigen Beschreibungen anzuzeigen.
// Weitere Informationen finden Sie unter https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python-Debugger: Remoteanfügung",
"type": "debugpy",
"request": "attach",
"connect": {
"host": "localhost",
"port": 5678
},
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "/home/lotzm/odoo-openupgrade-wizard"
}
]
}
]
}

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"python.defaultInterpreterPath": "/home/lotzm/.local/share/pipx/venvs/odoo-openupgrade-wizard/bin/python"
}

View File

@ -6,6 +6,167 @@ This file compiles releases and changes made in
.. towncrier release notes start
odoo-openupgrade-wizard 1.3.1 (2025-09-18)
==========================================
Bugfixes
--------
- Fix BSD mkdir incompatibility on macOS by using single-character
flags for 'mode' and 'parents' for cross-platform folder creation (#39)
- Fix debian buster Dockerfile. It uses the old https://deb.debian.org
instead of https://archive.debian.org.
- Improve error handling for missing config file outside initialized
environment.
- Prevent creating a log file outside of an initialized directory.
- Set 'rm=True' when building Docker images, ensuring intermediate (i.e.
orphaned) containers are automatically removed after builds and keeping
local Docker environments clean.
By default, the docker build CLI now sets --rm=true, but the SDK has
kept the old default of False to preserve backward compatibility.
Documentation
-------------
- Many improvements/additions to README.md and help string, including missing
Command help, additional examples, a Quick Start Guide, standard technical
writing changes, etc.
- Remove obsolete ROADMAP file. Team now uses issues on gitlab.
Misc
----
- Do not set False to an argument that is hint typed as string. Using None
instead.
odoo-openupgrade-wizard 1.3.0 (2025-05-04)
==========================================
Features
--------
- Disable default Odoo memory limit (of 2560 MiB) by default.
This can be adjusted in the `odoo.conf` file for each version.
Documentation
-------------
- Improve release documentation for developpers.
Misc
----
- set a default 'postgres' database in ``oow psql`` command, to avoid
force user to set a database, in case of dbless command.
odoo-openupgrade-wizard 1.2.0 (2025-04-12)
==========================================
Features
--------
- Add an option ``update`` in the configuration file at migration_step level.
If disabled, the update=all step will be skipped during this step.
That can be interesting to save time, during the first and the last steps of the migration
process (when ``execution_context='regular'``).
- Improve workload analysis file with button to hide done module.
Bugfixes
--------
- Handles the case where the filestore data provided in the source is in a "filestore" subfolder.
Misc
----
- restoredb: Use builtins click feature to check if provided paths exist
- Refactoring of the function tools.tools_odoo.generate_odoo_command.
odoo-openupgrade-wizard 1.1.0 (2024-11-07)
==========================================
Features
--------
- Support 17.0 serie.
- Support 18.0 serie.
- add a new command ``odoo-openupgrade-wizard guess-requirement`` that
initialize the python and bin requirements files, based on the odoo
modules present in the modules.csv file, and analyzing code.
(``__manifest__.py`` and ``setup.py`` files)
Misc
----
- Add support of python 3.13.
- Test only on the first and the last supported python version. (python3.9 and
python3.13).
This change allow to save time and resources on CI execution.
odoo-openupgrade-wizard 1.0.3 (2024-10-09)
==========================================
Bugfixes
--------
- Fix crash when building container fails.
- Make odoo openupgrade wizard working in the following combination:
Odoo version <= 12 + Postgresql version >= 14
- New fix for error that append randomly when removing a container.
Documentation
-------------
- Add towncrier and newsfragments info in dev documentation.
- Improve the README.md file, hightlighting code section.
- Update contributors list until October 2024
Misc
----
- Update of python libraries version, using ``poetry update``.
* Removing incremental (22.10.0)
* Updating attrs (23.2.0 -> 24.2.0)
* Updating certifi (2024.2.2 -> 2024.8.30)
* Updating filelock (3.13.2 -> 3.16.1)
* Updating idna (3.6 -> 3.10)
* Updating packaging (24.0 -> 24.1)
* Updating platformdirs (4.2.0 -> 4.3.6)
* Updating pygments (2.17.2 -> 2.18.0)
* Updating pyyaml (6.0.1 -> 6.0.2)
* Updating tomli (2.0.1 -> 2.0.2)
* Updating typing-extensions (4.10.0 -> 4.12.2)
* Updating urllib3 (2.2.1 -> 2.2.3)
* Updating zipp (3.18.1 -> 3.20.2)
* Updating argcomplete (3.2.3 -> 3.5.1)
* Updating astroid (3.1.0 -> 3.3.5)
* Updating coverage (7.4.4 -> 7.6.1)
* Updating dill (0.3.8 -> 0.3.9)
* Updating gitpython (3.1.42 -> 3.1.43)
* Updating jinja2 (3.1.3 -> 3.1.4)
* Updating requests (2.31.0 -> 2.32.3)
* Updating rich (13.7.1 -> 13.9.2)
* Updating setuptools (69.2.0 -> 75.1.0)
* Updating tomlkit (0.12.4 -> 0.13.2)
* Updating virtualenv (20.25.1 -> 20.26.6)
* Updating docker (7.0.0 -> 7.1.0)
* Updating plumbum (1.8.2 -> 1.9.0)
* Updating pylint (3.1.0 -> 3.3.1)
* Updating towncrier (23.11.0 -> 24.8.0)
odoo-openupgrade-wizard 1.0.2 (2024-10-06)
==========================================

View File

@ -11,6 +11,8 @@
* Boris GALLET, since September 2024
* Ahmet YIĞIT BUDAK, from [Altinkaya](https://www.altinkaya.com/fr), since October 2024
* Alexandre AUBIN, from [Coopaname](https://www.coopaname.coop/), since October 2024
* Sergio Zanchetta, from [PNLug](https://www.pnlug.it/), since January 2025
* Ken WOYCHESKO, since May 2025
# Reviewers

View File

@ -88,6 +88,37 @@ docker exec -it POSTGRES_CONTAINER_NAME /bin/bash
# Contribute
## Provide newsfragments in your merge requests
If you propose a merge request, please add a newsfragments with it.
A newsfragment is a small file describing what is done in the merge
request. The file has a extension (e.g. `.feature`, `.bugfix`, etc) that
describe witch type of modification you are doing. This newsfragment
file will populate the CHANGES.rst file for the next release.
Documentation and the full list of default available extension can be
found [here](https://towncrier.readthedocs.io/en/stable/tutorial.html#creating-news-fragments).
Newsfragments must be put in the `newsfragments` directory at the root
of the project. You can install `towncrier` via `pipx install
towncrier`.
The newsfragments file will be processed with `towncrier` by the
maintainers during the release process.
Use `towncrier create --help` to see the available extension for the
newsfragement files. The name of the file can be a number referring an
issue of the project or a
[slug](https://en.wikipedia.org/wiki/Clean_URL#Slug) that start with
a `+` symbol.
This is a example of newsfragments.
`newsfragments/+sub-command-cowsay.feature`:
```
Adds a new subcommand `cowsay` to allow poeple to speak like a cow.
```
## Add python dependencies
If you add new dependencies, you have to:
@ -121,6 +152,14 @@ release, if it is a major, minor or patch release. For alpha, beta, etc
release information will be published with the next major, minor or
patch release.
To generate the `CHANGES.rst`, run the towncrier tool:
```sh
towncrier build
```
Use `--draft` option to preview the result.
Then push a commit with the version and the changlog updated on the main
branch.

19
PATCH.md Normal file
View File

@ -0,0 +1,19 @@
# Loakale Entwicklung an oow
Das geht am einfachsten mit **pipx** im "editable mode" (`--editable`), sodass Änderungen im Arbeitsverzeichnis sofort wirksam sind.
Angenommen, dein Arbeitsverzeichnis ist odoo-openupgrade-wizard, dann führe im Terminal aus:
```bash
pipx install --editable /home/lotzm/gitea.hobbyhimmel/odoo-openupgrade-wizard
```
Dadurch wird ein Symlink auf dein Arbeitsverzeichnis erstellt und du kannst direkt am Code arbeiten.
Das Kommando `oow` ist dann wie gewohnt verfügbar, aber nutzt immer den aktuellen Stand deines Codes.
**Hinweis:**
Falls du vorher schon eine pipx-Installation hattest, führe vorher aus:
```bash
pipx uninstall odoo-openupgrade-wizard
```
Danach kannst du Änderungen im Arbeitsverzeichnis machen und direkt testen!

999
README.md

File diff suppressed because it is too large Load Diff

View File

@ -1 +0,0 @@
Update contributors list until October 2024

View File

@ -1,3 +1,10 @@
#import debugpy
#debugpy.listen(("0.0.0.0", 5678))
#print("⏳ Warten auf Debugger-Anbindung (VS Code: Python: Remote Attach)...")
#debugpy.wait_for_client()
#print("✅ Debugger verbunden!")
import datetime
import logging
import sys
@ -24,6 +31,7 @@ from odoo_openupgrade_wizard.cli.cli_generate_module_analysis import (
generate_module_analysis,
)
from odoo_openupgrade_wizard.cli.cli_get_code import get_code
from odoo_openupgrade_wizard.cli.cli_guess_requirement import guess_requirement
from odoo_openupgrade_wizard.cli.cli_init import init
from odoo_openupgrade_wizard.cli.cli_install_from_csv import install_from_csv
from odoo_openupgrade_wizard.cli.cli_psql import psql
@ -48,9 +56,9 @@ DEFAULT_MODULES_FILE = "modules.csv"
writable=True,
resolve_path=True,
),
help="Folder that will contains all the configuration of the wizard"
" and all the Odoo code required to make the migrations. Let empty to"
" use current folder (./).",
help="Directory that will contain all the configuration of the wizard "
"and all the Odoo code required to perform the migrations. Leave "
"empty to use current directory (./).",
)
@click.option(
"-c",
@ -61,7 +69,7 @@ DEFAULT_MODULES_FILE = "modules.csv"
),
help=(
f"Configuration file to use. By default, a file named "
f'"{DEFAULT_CONFIG_FILE}" in the environment folder will be used.'
f'"{DEFAULT_CONFIG_FILE}" in the environment directory will be used.'
),
)
@click.option(
@ -72,7 +80,7 @@ DEFAULT_MODULES_FILE = "modules.csv"
),
help=(
f"Modules file to use. By default, a file named "
f'"{DEFAULT_MODULES_FILE}" in the environment folder will be used.'
f'"{DEFAULT_MODULES_FILE}" in the environment directory will be used.'
),
)
@click.option(
@ -80,17 +88,23 @@ DEFAULT_MODULES_FILE = "modules.csv"
type=click.Path(
exists=True, file_okay=False, writable=True, resolve_path=True
),
help="Folder that contains the Odoo filestore of the database(s)"
" to migrate. Let empty to use the subfolder 'filestore' of the"
" environment folder.",
help="Directory that contains the Odoo filestore of the database(s) to "
"migrate. Leave empty to use the subdirectory 'filestore' of the "
"environment directory.",
)
@click.option("-l", "--log-level", type=LogLevel(), default=logging.INFO)
@click.pass_context
def main(
ctx, env_folder, config_file, modules_file, filestore_folder, log_level
):
"""
Provides a command set to perform odoo Community Edition migrations.
"""Provides a command set to perform Odoo Community Edition migrations.
Instructions are provided in the README.md file, or see the
help provided for each 'Command' listed below. For
example, to learn more about the `init` command,
run:
`oow init --help`
"""
date_begin = datetime.datetime.now()
logger.remove()
@ -110,16 +124,6 @@ def main(
script_folder_path = env_folder_path / Path("./scripts/")
log_folder_path = env_folder_path / Path("./log/")
# ensure log folder exists
ensure_folder_exists(log_folder_path, git_ignore_content=True)
# Create log file
log_prefix = "{}__{}".format(
date_begin.strftime("%Y_%m_%d__%H_%M_%S"), ctx.invoked_subcommand
)
log_file_path = log_folder_path / Path(log_prefix + ".log")
logger.add(log_file_path)
if config_file:
config_file_path = Path(config_file)
else:
@ -130,24 +134,38 @@ def main(
else:
module_file_path = env_folder_path / Path(DEFAULT_MODULES_FILE)
if config_file_path.exists():
# Load the main configuration file
with open(config_file_path) as file:
config = yaml.safe_load(file)
ctx.obj["config"] = config
# ensure log folder exists
ensure_folder_exists(log_folder_path, git_ignore_content=True)
# Create log file
log_prefix = "{}__{}".format(
date_begin.strftime("%Y_%m_%d__%H_%M_%S"), ctx.invoked_subcommand
)
log_file_path = log_folder_path / Path(log_prefix + ".log")
logger.add(log_file_path)
ctx.obj["log_prefix"] = log_prefix
elif ctx.invoked_subcommand not in ("init", None):
ctx.fail(
f"Environment not initialized. "
f"Expected config file at: {config_file_path}",
)
# Add all global values in the context
ctx.obj["env_folder_path"] = env_folder_path
ctx.obj["src_folder_path"] = src_folder_path
ctx.obj["filestore_folder_path"] = filestore_folder_path
ctx.obj["script_folder_path"] = script_folder_path
ctx.obj["log_folder_path"] = log_folder_path
ctx.obj["log_prefix"] = log_prefix
ctx.obj["config_file_path"] = config_file_path
ctx.obj["module_file_path"] = module_file_path
# Load the main configuration file
if config_file_path.exists():
with open(config_file_path) as file:
config = yaml.safe_load(file)
ctx.obj["config"] = config
elif ctx.invoked_subcommand != "init":
raise
main.add_command(copydb)
main.add_command(restoredb)
@ -158,6 +176,7 @@ main.add_command(estimate_workload)
main.add_command(execute_script_python)
main.add_command(execute_script_sql)
main.add_command(generate_module_analysis)
main.add_command(guess_requirement)
main.add_command(get_code)
main.add_command(init)
main.add_command(install_from_csv)

View File

@ -10,17 +10,20 @@ from odoo_openupgrade_wizard.tools import (
"-s",
"--source",
type=str,
help="Name of the database to copy",
help="Name of the source database to copy.",
)
@click.option(
"-d",
"--dest",
type=str,
help="Name of the new database",
help="Name of the destination database to create.",
)
@click.pass_context
def copydb(ctx, source, dest):
"""Create an Odoo database by copying an existing one.
it will copy the postgres database and the filestore.
"""Create a new Odoo database by copying another.
This command duplicates both the PostgreSQL database and its associated
filestore.
"""
click_odoo_contrib.copydb(ctx, source, dest)

View File

@ -17,11 +17,16 @@ from odoo_openupgrade_wizard.tools.tools_system import get_local_user_id
@versions_options
@click.pass_context
def docker_build(ctx, versions):
"""Build Odoo Docker Images and pull Postgres image"""
"""Build Docker images and pull PostgreSQL image.
This command prepares the Docker environment needed for running migration
steps. Make sure to run `oow get-code` first to ensure all required code
and requirements files are available for each version.
"""
# Pull DB image
logger.info(
"Pulling the postgresql docker image. This can take a while..."
"Pulling the PostgreSQL Docker image. This can take a while..."
)
pull_image(ctx.obj["config"]["postgres_image_name"])
@ -32,16 +37,16 @@ def docker_build(ctx, versions):
)
if not odoo_requirement_file_path.exists():
logger.error(
"Building Odoo docker image for version {odoo_version}, "
"Cannot build Odoo Docker image for version {odoo_version}, "
"because file {odoo_requirement_file_path} cannot be found. "
"Have your run the get-code command ?",
"Have you run the get-code command?",
odoo_version=odoo_version,
odoo_requirement_file_path=odoo_requirement_file_path,
)
continue
logger.info(
f"Building Odoo docker image for version '{odoo_version}'."
f"Building Odoo Docker image for version '{odoo_version}'."
" This can take a while..."
)
image = build_image(

View File

@ -17,33 +17,34 @@ from odoo_openupgrade_wizard.tools.tools_system import dump_filestore
"--database-path",
type=click.Path(writable=True, resolve_path=True),
required=True,
help="Path to the database dump relative project folder.",
help="Destination path for the database dump relative to the project "
"directory.",
)
@click.option(
"--database-format",
type=click.Choice(("p", "c", "d", "t")),
default="c",
help="Database format (see pg_dump options): plain sql text (p), "
"custom format compressed (c), directory (d), tar file (t).",
help="Database format (see pg_dump options): plain SQL (p), "
"custom format compressed (c), directory (d), or tar file (t).",
)
@click.option(
"--filestore-path",
type=click.Path(writable=True, resolve_path=True),
required=True,
help="Path to the filestore backup.",
help="Destination path for the filestore backup.",
)
@click.option(
"--filestore-format",
type=click.Choice(("d", "t", "tgz")),
default="tgz",
help="Filestore format: directory (d), tar file (t), "
"tar file compressed with gzip (tgz)",
"or tar file compressed with gzip (tgz)",
)
@click.option(
"--force",
is_flag=True,
default=False,
help="Overwrite file if they already exists.",
help="Overwrite files if they already exist.",
)
@click.pass_context
def dumpdb(
@ -55,7 +56,14 @@ def dumpdb(
filestore_format,
force,
):
"""Create an dump of an Odoo database and its filestore."""
"""Create a dump of an Odoo database and filestore.
Creates a backup of the selected Odoo database and
its associated filestore. Both output locations must
reside inside the project directory. Existing files
will be overwritten if --force is specified.
"""
database_path = pathlib.Path(database_path)
filestore_path = pathlib.Path(filestore_path)
@ -67,7 +75,7 @@ def dumpdb(
):
ctx.fail(
"database-path should be inside the project path to allow "
"postgresql to write to it."
"PostgreSQL to write to it."
)
# Fail if dumps already exists and force argument not given

View File

@ -17,35 +17,43 @@ from odoo_openupgrade_wizard.tools.tools_system import (
dir_okay=False,
),
default="./analysis.html",
help="Path where the HTML analysis report will be saved. "
"Default is './analysis.html'",
)
@click.option(
"--extra-modules",
"extra_modules_list",
# TODO, add a callback to check the quality of the argument
help="Coma separated modules to analyse. If not set, the modules.csv"
" file will be used to define the list of module to analyse."
"Ex: 'account,product,base'",
help="Comma-separated list of modules to analyze. If not set, "
"modules.csv will be used. Example: 'account,product,base'.",
)
@click.option(
"--time-unit",
type=click.Choice(["hour", "minute", "separator"]),
default="separator",
show_default=True,
help="Select unit to display time in the report. "
help="Format to use for displaying time in the report. "
"*separator* display time as `HHH<sep>MM`, "
"*hour* display time as decimal hour, "
"*min* display time as minute (rounded).",
"*min* display time as minutes (rounded).",
)
@click.option(
"--time-separator",
default=":",
help="Specify time separator, if time-unit is separator. "
"Default to `:` (it will produce time like this HHH:MM).",
help="Character to use as a separator in time output. "
"Used only if --time-unit=separator. Default is ':' (e.g. HHH:MM).",
)
@click.pass_context
def estimate_workload(
ctx, analysis_file_path, extra_modules_list, time_unit, time_separator
):
"""Estimate workload and create an analysis report.
This command estimates the workload required for an Odoo
migration based on the module set provided. The output is
an HTML report showing time estimations for each module.
"""
# Analyse
analysis = Analysis(ctx)

View File

@ -22,11 +22,29 @@ from odoo_openupgrade_wizard.tools.tools_odoo import (
exists=True,
dir_okay=False,
),
help="List of python files that will be executed, replacing the default"
" scripts placed in the migration step folder.",
help="""List of Python files to execute, with either an absolute path
or path relative to the project directory. With either method, the
path must be located inside the project directory so that the
Docker container can access it.
Files will be executed in
the order listed. If no files are specified, all Python (.py) files
in the `step` directory will be sorted alphabetically and then
executed in order.
See README.md for more information and examples.""",
)
@click.pass_context
def execute_script_python(ctx, step, database, script_file_path):
"""Execute Python scripts for a migration step.
Executes one or more custom Python scripts in the context of a specific
migration step, using the Odoo shell (with full ORM access). This command
allows you to manually run Python logic outside of the default
post-migration.py file for a given step. It allows fine-tuning
of migration behavior by manually specifying logic.
"""
migration_step = get_migration_step_from_options(ctx, step)
execute_click_odoo_python_files(

View File

@ -22,11 +22,21 @@ from odoo_openupgrade_wizard.tools.tools_postgres import (
exists=True,
dir_okay=False,
),
help="List of SQL files that will be executed, replacing the default"
" scripts placed in the migration step folder.",
help="List of SQL files to execute. Files will be executed in the order "
"listed. If no files are specified, all SQL files (.sql) in the "
"step's directory will be sorted alphabetically and then executed "
"in order.",
)
@click.pass_context
def execute_script_sql(ctx, step, database, script_file_path):
"""Execute SQL scripts for a migration step.
Executes one or more custom SQL scripts against the specified database,
using the PostgreSQL Docker container. This command allows you to manually
run SQL logic, allowing you to test or apply SQL changes in the context
of a specific migration step outside the automatic oow upgrade process.
"""
migration_step = get_migration_step_from_options(ctx, step)
execute_sql_files_pre_migration(

View File

@ -28,11 +28,24 @@ from odoo_openupgrade_wizard.tools.tools_system import ensure_folder_writable
"-m",
"--modules",
type=str,
help="Coma-separated list of modules to analysis."
" Let empty to analyse all the Odoo modules.",
help="Comma-separated list of modules to analyse."
" Leave empty to analyse all the Odoo modules.",
)
@click.pass_context
def generate_module_analysis(ctx, step, database, modules):
"""Analyzes changes in data model & module data.
Performs an analysis between the target version (represented by the step
parameter) and the previous version to indicate how the data model and
module data have changed between the two versions (uses the
OCA/server-tools `upgrade_analysis` tool internally).
You can also use this function to analyze differences for custom & OCA
modules between several versions (e.g. in case of refactoring).
See the README.md for more information, including the location of the
resultant analysis files.
"""
migration_steps = get_migration_steps_from_options(ctx, step - 1, step)
initial_step = migration_steps[0].copy()

View File

@ -19,11 +19,15 @@ from odoo_openupgrade_wizard.tools.tools_system import git_aggregate
type=int,
default=10,
help="Jobs used to call the git-aggregate command."
" reasonably set to 10 by default.",
" Reasonably set to 10 by default.",
)
@click.pass_context
def get_code(ctx, versions, jobs):
"""Get code by running gitaggregate command for each version"""
"""Get all required source code for each version.
Downloads all required Odoo source code and dependencies for each version
defined in your migration (uses the `gitaggregate` tools internally).
"""
for odoo_version in get_odoo_versions_from_options(ctx, versions):
folder_path = get_odoo_env_path(ctx, odoo_version)

View File

@ -0,0 +1,61 @@
from pathlib import Path
import click
from odoo_openupgrade_wizard.tools.tools_odoo import (
get_odoo_env_path,
get_odoo_modules_from_csv,
)
from odoo_openupgrade_wizard.tools.tools_odoo_module import Analysis
from odoo_openupgrade_wizard.tools.tools_system import (
ensure_file_exists_from_template,
)
@click.command()
@click.option(
"--extra-modules",
"extra_modules_list",
# TODO, add a callback to check the quality of the argument
help="Comma-separated list of modules to analyze. If not set, "
"modules.csv will be used. Example: 'account,product,base'.",
)
@click.pass_context
def guess_requirement(ctx, extra_modules_list):
"""Guess system & Python requirements for modules.
Analyzes the list of modules defined in your modules.csv file
to generate the required Python and Debian package dependencies per
environment.
For each module and each version, this command tries to parse the
corresponding __manifest__.py file (and, if present, the setup.py
file). It then appends any discovered requirements to the appropriate
addons_debian_requirements.txt and addons_python_requirements.txt files
present in each env directory.
"""
# Analyse
analysis = Analysis(ctx)
if extra_modules_list:
module_list = extra_modules_list.split(",")
else:
module_list = get_odoo_modules_from_csv(ctx.obj["module_file_path"])
analysis.analyse_module_version(ctx, module_list)
analysis.analyse_missing_module()
result = analysis.get_requirements(ctx)
for odoo_version in [x for x in ctx.obj["config"]["odoo_versions"]]:
path_version = get_odoo_env_path(ctx, odoo_version)
ensure_file_exists_from_template(
path_version / Path("addons_python_requirements.txt"),
"odoo/addons_python_requirements.txt.j2",
dependencies=result[odoo_version]["python"],
)
ensure_file_exists_from_template(
path_version / Path("addons_debian_requirements.txt"),
"odoo/addons_debian_requirements.txt.j2",
dependencies=result[odoo_version]["bin"],
)

View File

@ -19,42 +19,44 @@ from odoo_openupgrade_wizard.tools.tools_system import (
required=True,
prompt=True,
type=str,
help="Name of your project without spaces neither special"
" chars or uppercases. exemple 'my-customer-9-12'."
" This will be used to tag with a friendly"
" name the odoo docker images.",
help="Name of your project without spaces, special"
" characters, or uppercases. Example: 'my-customer-9-12'."
" This will be used to tag the Odoo Docker images "
" with a friendly name.",
)
@click.option(
"--initial-version",
required=True,
prompt=True,
type=click.Choice(get_version_options("initial")),
help="Initial Odoo version to migrate from.",
)
@click.option(
"--final-version",
required=True,
prompt=True,
type=click.Choice(get_version_options("final")),
help="Target Odoo version to migrate to.",
)
@click.option(
"--postgresql-version",
required=True,
prompt=True,
help="The version of postgresql that will be used"
" to create the postgresql container.Ex : '9.1', '16', ..."
" The version should be available in docker hub."
" (https://hub.docker.com/_/postgres)"
" avoid the 'latest' version if you want a deterministic installation."
" Key Point: If your current production server uses Postgresql version A"
" and if your future production server usees Postgresql version B,"
" you should select here a version X, with A <= X <= B.",
help="""The version of PostgreSQL that will be used
to create the PostgreSQL container. Example: '9.1', '16', etc.
The version should be available in Docker hub.
(https://hub.docker.com/_/postgres)
Avoid the 'latest' version if you want a deterministic installation.
Key Point: If your current production server uses PostgreSQL version A
and your future production server will use PostgreSQL version B,
you should select here a version X, with A <= X <= B.""",
)
@click.option(
"--extra-repository",
"extra_repository_list",
# TODO, add a callback to check the quality of the argument
help="Coma separated extra repositories to use in the odoo environment."
"Ex: 'OCA/web,OCA/server-tools,GRAP/grap-odoo-incubator'",
help="Comma-separated extra repositories to use in the Odoo environment."
"Example: 'OCA/web,OCA/server-tools,GRAP/grap-odoo-incubator'",
)
@click.pass_context
def init(
@ -65,8 +67,10 @@ def init(
postgresql_version,
extra_repository_list,
):
"""Initialize OOW Environment based on the initial and
the final version of Odoo you want to migrate.
"""Initialize the OOW project environment.
This command sets up the project folder structure, configuration
files, and default templates needed to begin an Odoo migration.
"""
# Handle arguments
@ -152,18 +156,30 @@ def init(
path_version = get_odoo_env_path(ctx, odoo_version)
ensure_folder_exists(path_version)
# Create python requirements file
# Create python requirements files
ensure_file_exists_from_template(
path_version / Path("extra_python_requirements.txt"),
"odoo/extra_python_requirements.txt.j2",
)
# Create debian requirements file
ensure_file_exists_from_template(
path_version / Path("addons_python_requirements.txt"),
"odoo/addons_python_requirements.txt.j2",
dependencies={},
)
# Create debian requirements files
ensure_file_exists_from_template(
path_version / Path("extra_debian_requirements.txt"),
"odoo/extra_debian_requirements.txt.j2",
)
ensure_file_exists_from_template(
path_version / Path("addons_debian_requirements.txt"),
"odoo/addons_debian_requirements.txt.j2",
dependencies={},
)
# Create odoo config file
ensure_file_exists_from_template(
path_version / Path("odoo.conf"),

View File

@ -20,6 +20,12 @@ from odoo_openupgrade_wizard.tools.tools_postgres import ensure_database
@demo_option
@click.pass_context
def install_from_csv(ctx, database, with_demo):
"""Install modules from a CSV file.
This command reads the modules.csv file and installs the
modules listed for a specific Odoo version. The database will be
created if it doesn't exist.
"""
migration_step = get_migration_step_from_options(ctx, 1)
ensure_database(ctx, database, state="present")

View File

@ -6,10 +6,8 @@ def versions_options(function):
"-v",
"--versions",
type=str,
help="Coma-separated values of odoo versions for which"
" you want to perform the operation."
" Let empty to perform the operation on all the versions"
" of the project",
help="Comma-separated Odoo versions to target. Leave empty to "
"perform the operation on all versions in the project",
)(function)
return function
@ -30,7 +28,7 @@ def first_step_option(function):
function = click.option(
"--first-step",
type=int,
help="First step for which to perform the operation",
help="First step to include in the operation.",
)(function)
return function
@ -39,7 +37,7 @@ def last_step_option(function):
function = click.option(
"--last-step",
type=int,
help="Last step for which to perform the operation",
help="Last step to include in the operation.",
)(function)
return function
@ -48,7 +46,7 @@ def demo_option(function):
function = click.option(
"--with-demo/--without-demo",
default=False,
help="Create database with or without demo data.",
help="Whether to include demo data when creating the database.",
)(function)
return function
@ -59,8 +57,9 @@ def database_option_required(function):
"--database",
required=True,
prompt=True,
default="postgres",
type=str,
help="Odoo Database for which you want to perform the operation.",
help="Name of the Odoo database to operate on. Default is 'postgres'.",
)(function)
return function

View File

@ -6,14 +6,29 @@ from odoo_openupgrade_wizard.tools.tools_postgres import execute_psql_command
@click.command(context_settings={"ignore_unknown_options": True})
@database_option_required
@click.option("-c", "--command", "request")
@click.option("--pager/--no-pager", default=True)
@click.option(
"-c",
"--command",
"request",
help="SQL command to execute inside the container.",
)
@click.option(
"--pager/--no-pager",
default=True,
help="Enable or disable pager when displaying output.",
)
@click.argument("psql_args", nargs=-1, type=click.UNPROCESSED)
@click.pass_context
def psql(ctx, request, database, pager, psql_args):
"""Run psql in the postgres container. Fill any parameters of psql
as PSQLARGS.
"""Run a SQL command in the PostgreSQL container.
This command executes the provided SQL command using `psql`
within the database container. Use --command for inline SQL
or pass additional arguments directly to psql via PSQLARGS.
See the README.md for more information.
"""
result = execute_psql_command(ctx, request, database, psql_args)
if pager:
click.echo_via_pager(result)

View File

@ -13,8 +13,12 @@ from odoo_openupgrade_wizard.tools.tools_system import execute_check_output
@versions_options
@click.pass_context
def pull_submodule(ctx, versions):
"""Pull submodule that contains repos.yml file, if define in config.yml"""
"""Pull the repos.yml file from a Git repository.
This command runs `git submodule update --init --recursive`
for the submodule that contains your `repos.yml` file.
This ensures all nested submodules are also fetched.
"""
for odoo_version in get_odoo_versions_from_options(ctx, versions):
version_cfg = (
ctx.obj["config"]["odoo_version_settings"][odoo_version] or {}

View File

@ -12,31 +12,30 @@ from odoo_openupgrade_wizard.tools.tools_system import restore_filestore
@click.option(
"--database-path",
required=True,
type=click.Path(readable=True, resolve_path=True),
help="Path to the database dump relative project folder.",
type=click.Path(readable=True, resolve_path=True, exists=True),
help="Path to the database dump (inside the environment folder).",
)
@click.option(
"--database-format",
required=True,
type=click.Choice(("c", "d", "t", "p")),
default="c",
help="Database format (see pg_dump options): "
"custom format compressed (c), directory (d), tar file (t),"
" plain sql text (p).",
help="Format of the database dump: custom (c), directory (d), tar (t), "
"or plain SQL (p).",
)
@click.option(
"--filestore-path",
required=True,
type=click.Path(readable=True, resolve_path=True),
help="Path to the filestore backup.",
type=click.Path(readable=True, resolve_path=True, exists=True),
help="Path to the filestore backup (inside the environment folder).",
)
@click.option(
"--filestore-format",
required=True,
type=click.Choice(("d", "t", "tgz")),
default="tgz",
help="Filestore format: directory (d), tar file (t), "
"tar file compressed with gzip (tgz)",
help="Format of the filestore: directory (d), tar (t), or gzip-compressed "
"tar (tgz).",
)
@click.pass_context
def restoredb(
@ -47,7 +46,13 @@ def restoredb(
filestore_path,
filestore_format,
):
"""Restore an Odoo database and associated filestore."""
"""Restore a database and its associated filestore.
This command restores a PostgreSQL database and its matching Odoo
filestore into the current OOW environment. The filestore and
database dump must be accessible from within the environment directory
so that the Docker container can read them during restore.
"""
database_path = Path(database_path)
filestore_path = Path(filestore_path)
@ -57,8 +62,9 @@ def restoredb(
if not str(database_path).startswith(str(absolute_env_folder_path)):
ctx.fail(
"database-path should be inside the project path to allow "
"postgresql to read to it."
"PostgreSQL to read it."
)
# Restore the database
output = execute_pg_restore(
ctx,

View File

@ -27,13 +27,13 @@ from odoo_openupgrade_wizard.tools.tools_postgres import ensure_database
"-i",
"--init-modules",
type=str,
help="List of modules to install. Equivalent to -i odoo options.",
help="List of modules to install. Equivalent to -i Odoo options.",
)
@click.option(
"-u",
"--update-modules",
type=str,
help="List of modules to update. Equivalent to -u odoo options.",
help="List of modules to update. Equivalent to -u Odoo options.",
)
@click.option(
"-e",
@ -41,7 +41,7 @@ from odoo_openupgrade_wizard.tools.tools_postgres import ensure_database
type=click.Choice(["regular", "openupgrade"]),
help="Force to use an openupgrade (OCA/openupgrade)"
" or a regular (odoo/odoo or OCA/OCB) base code when running odoo."
" Let empty to use the defaut execution of the migration step.",
" Leave empty to use the default execution of the migration step.",
)
@click.pass_context
def run(
@ -54,6 +54,14 @@ def run(
update_modules,
execution_context,
):
"""Run Odoo for a specific migration step.
The database will be created if it doesn't already exist. Unless the
`stop-after-init` flag is used, the Odoo instance will be available
on your host at the following URL: http://localhost:9069
(port depends on the `host_odoo_xmlrpc_port` setting in your
`config.yml` file).
"""
migration_step = get_migration_step_from_options(ctx, step)
ensure_database(ctx, database, state="present")
try:

View File

@ -25,11 +25,22 @@ from odoo_openupgrade_wizard.tools.tools_postgres import (
@demo_option
@click.pass_context
def upgrade(ctx, first_step, last_step, database, with_demo):
"""Performs the full db migration across all steps.
For each step, this will:
1. Run `pre-migration.sql` scripts.
2. Apply "update all" (in an upgrade or update context).
3. Run `post-migration.py` scripts via XML-RPC/Odoo shell (via `odoorpc`).
"""
migration_steps = get_migration_steps_from_options(
ctx, first_step, last_step
)
for migration_step in migration_steps:
execute_sql_files_pre_migration(ctx, database, migration_step)
if migration_step.get("update", True):
try:
run_odoo(
ctx,
@ -44,4 +55,15 @@ def upgrade(ctx, first_step, last_step, database, with_demo):
logger.info("Received Keyboard Interrupt or System Exiting...")
finally:
kill_odoo(ctx, database, migration_step)
elif migration_step.get("execution_context") == "openupgrade":
raise ValueError(
"Incorrect setting 'update: True'"
" and 'execution_context: openupgrade'"
)
else:
logger.info(
"Skip update=all for"
f" step {migration_step.get('complete_name')}"
)
execute_click_odoo_python_files(ctx, database, migration_step)

View File

@ -2,7 +2,15 @@ from pathlib import Path
from loguru import logger
_ALL_ODOO_VERSIONS = [8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0]
FIRST_ODOO_VERSION_SUPPORTED = 8
LAST_ODOO_VERSION_SUPPORTED = 18
_ALL_ODOO_VERSIONS = [
float(x)
for x in range(
FIRST_ODOO_VERSION_SUPPORTED, LAST_ODOO_VERSION_SUPPORTED + 1
)
]
def get_version_options(mode: str) -> list:
@ -43,7 +51,7 @@ def get_odoo_run_command(migration_step: dict) -> str:
def get_odoo_folder(
migration_step: dict, execution_context: str = False
migration_step: dict, execution_context: str = None
) -> str:
"""return the main odoo folder, depending on the migration step.
(./src/odoo, ./src/openupgrade, ...)"""
@ -92,7 +100,7 @@ def skip_addon_path(migration_step: dict, path: Path) -> bool:
def get_server_wide_modules_upgrade(
migration_step: dict, execution_context: str = False
migration_step: dict, execution_context: str = None
) -> list:
"""return a list of modules to load, depending on the migration step."""
if (
@ -118,7 +126,7 @@ def get_upgrade_analysis_module(migration_step: dict) -> str:
def generate_records(odoo_instance, migration_step: dict):
logger.info(
"Generate Records in version %s..."
" (It can take a while)" % (migration_step["version"])
" (This may take a while)" % (migration_step["version"])
)
if migration_step["version"] < 14.0:
wizard = odoo_instance.browse_by_create(

View File

@ -1,4 +1,23 @@
<html>
<head>
<script>
function ShowAll(){
var elements = document.getElementsByClassName('work_done');
for (var i = 0; i < elements.length; i ++) {
elements[i].style.display = 'table-row';
}
}
function HideWorkDone(){
var elements = document.getElementsByClassName('work_done');
for (var i = 0; i < elements.length; i ++) {
elements[i].style.display = 'none';
}
}
</script>
</head>
<body>
<h1>Migration Analysis</h1>
<table border="1" width="100%">
@ -18,6 +37,14 @@
<td>{{ current_date }}</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="4" style="text-align: center;">
<a href="#" onclick="ShowAll()">Show All Modules</a>
<a href="#" onclick="HideWorkDone()">Hide Done Modules</a>
</td>
</tr>
</tfoot>
</table>
<h2>Summary</h2>
@ -33,29 +60,31 @@
<tr>
<td>Odoo</td>
<td>{{ analysis.get_module_qty('odoo') }}</td>
<td>{{ analysis.workload_hour_text('odoo') }}</td>
<td>{{ time_to_text(analysis.workload('odoo', False)) }}</td>
</tr>
<tr>
<td>OCA</td>
<td>{{ analysis.get_module_qty('oca') }}</td>
<td>{{ analysis.workload_hour_text('oca') }}</td>
<td>{{ time_to_text(analysis.workload('oca', False)) }}</td>
</tr>
<tr>
<td>Custom</td>
<td>{{ analysis.get_module_qty('custom') }}</td>
<td>{{ analysis.workload_hour_text('custom') }}</td>
<td>{{ time_to_text(analysis.workload('custom', False)) }}</td>
</tr>
{%- if analysis.get_module_qty('not_found') -%}
<tr>
<td>Not Found</td>
<td>{{ analysis.get_module_qty('not_found') }}</td>
<td>&nbsp;</td>
</tr>
{%- endif -%}
</tbody>
<tfood>
<tr>
<th>Total</th>
<td>{{ analysis.get_module_qty() }}</td>
<td>{{ analysis.workload_hour_text() }}</td>
<td>{{ time_to_text(analysis.workload(False, False)) }}</td>
</tr>
</tfood>
</table>
@ -66,116 +95,100 @@
<tr>
<th>&nbsp;</th>
<th>Total</th>
{%- for odoo_version in ctx.obj['config']['odoo_versions'] -%}
{%- for odoo_version in ctx.obj['config']['odoo_versions'] %}
<th>{{ odoo_version }}</th>
{% endfor %}
{%- endfor %}
</tr>
</thead>
<tbody>
{% set ns = namespace(
current_repository='',
current_module_type='',
) %}
{% for odoo_module in analysis.modules %}
{%- set ns = namespace(current_repository='', current_module_type='') %}
<!-- ---------------------- -->
<!-- Handle New Module Type -->
<!-- ---------------------- -->
{%- for odoo_module in analysis.modules %}
{%- if (ns.current_module_type != odoo_module.module_type) %}
{%- set ns.current_module_type = odoo_module.module_type %}
{% if (
ns.current_module_type != odoo_module.module_type
and odoo_module.module_type != 'odoo') %}
{% set ns.current_module_type = odoo_module.module_type %}
<!-- ------------------------------------------------ -->
<!-- Handle New Module Type {{ns.current_module_type}}-->
<!-- ------------------------------------------------ -->
<tr>
<th colspan="{{2 + ctx.obj['config']['odoo_versions']|length}}">
{{ ns.current_module_type}}
<h3>{{ odoo_module.module_type}}</h3>
</th>
<tr>
{% endif %}
{%- endif %}
<!-- -------------------- -->
<!-- Handle New Repository-->
<!-- -------------------- -->
{%- if ns.current_repository != odoo_module.repository %}
{%- set ns.current_repository = odoo_module.repository %}
{%- set repository_workload = analysis.workload(False, odoo_module.repository) %}
{% if ns.current_repository != odoo_module.repository %}
{% set ns.current_repository = odoo_module.repository %}
<!-- ---------------------------------------------- -->
<!-- Handle New Repository {{ns.current_repository}}-->
<!-- ---------------------------------------------- -->
{% if ns.current_repository %}
<tr>
{%- if ns.current_repository %}
<tr class="{{repository_workload == 0 and 'work_done' or ''}}">
<th colspan="{{2 + ctx.obj['config']['odoo_versions']|length}}">
{{ ns.current_repository}}
<h4>{{ odoo_module.repository}}
{% if repository_workload %}
({{ time_to_text(repository_workload) }})
{% endif %}
</h4>
</th>
<tr>
{% endif %}
{% endif %}
{%- endif %}
{%- endif %}
<!-- -------------------- -->
<!-- Display Module Line -->
<!-- -------------------- -->
<tr>
<tr class="{{odoo_module.workload == 0 and 'work_done' or ''}}">
<td>{{odoo_module.name}}
{% if odoo_module.module_type == 'not_found' %}
{% set odoo_apps_url = odoo_module.get_odoo_apps_url() %}
{% if odoo_apps_url %}
{%- if odoo_module.module_type == 'not_found' -%}
{%- set odoo_apps_url = odoo_module.get_odoo_apps_url() -%}
{%- if odoo_apps_url -%}
<a href="{{odoo_apps_url}}" target="_blank">AppsStore</a>
{% else %}
{% set odoo_code_search_url = odoo_module.get_odoo_code_search_url() %}
{% if odoo_code_search_url %}
<a href="{{odoo_code_search_url}}" target="_blank">
OdooCodeSearch
</a>
{% endif %}
{% endif %}
{% endif %}
{%- else -%}
{%- set odoo_code_search_url = odoo_module.get_odoo_code_search_url() -%}
{%- if odoo_code_search_url -%}
<a href="{{odoo_code_search_url}}" target="_blank">OdooCodeSearch</a>
{%- endif -%}
{%- endif -%}
{%- endif -%}
</td>
<td>
{% if odoo_module.workload %}
{%- if odoo_module.workload -%}
{{time_to_text(odoo_module.workload)}}
{% endif %}
{%- endif -%}
</td>
{% for version in odoo_module.analyse.all_versions %}
{% set module_version = odoo_module.get_module_version(version) %}
{% if module_version %}
{% set size_text = module_version.get_size_text() %}
{% set analysis_text = module_version.get_analysis_text() %}
{% set workload = module_version.workload %}
{%- for version in odoo_module.analyse.all_versions %}
{%- set module_version = odoo_module.get_module_version(version) %}
{%- if module_version %}
{%- set size_text = module_version.get_size_text() %}
{%- set analysis_text = module_version.get_analysis_text() %}
{%- set workload = module_version.workload %}
<td style="background-color:{{module_version.get_bg_color()}};">
{{module_version.get_text()}}
{% if workload %}
<span style="background-color:lightblue;">
({{time_to_text(workload)}})
</span>
{% endif %}
{% if size_text %}
{%- if workload -%}
<span style="background-color:lightblue;">({{time_to_text(workload)}})</span>
{%- endif -%}
{%- if size_text -%}
<br/>
<span style="color:gray;font-size:11px;font-family:monospace;">({{ size_text}})</span>
{%- endif -%}
{%- if analysis_text -%}
<br/>
<span style="color:gray;font-size:11px;font-family:monospace;">
({{ size_text}})
<a href="{{module_version.analysis_url()}}" target="_blank">({{ analysis_text}})</a>
</span>
{% endif %}
{% if analysis_text %}
<br/>
<span style="color:gray;font-size:11px;font-family:monospace;">
<a href="{{module_version.analysis_url()}}" target="_blank">
({{ analysis_text}})
</a>
</span>
{% endif %}
{%- endif %}
</td>
{% else %}
{%- else %}
<td style="background-color:gray;">&nbsp;</td>
{% endif %}
{% endfor %}
{%- endif %}
{%- endfor %}
</tr>
{% endfor %}
{%- endfor %}
</tbody>
</table>

View File

@ -31,6 +31,9 @@ migration_steps:
version: {{ step['version'] }}
execution_context: {{ step['execution_context'] }}
complete_name: {{ step['complete_name'] }}
{%- if step['execution_context'] == 'regular'%}
update: True
{%- endif %}
{% endfor %}
workload_settings:

View File

@ -13,7 +13,7 @@ RUN apt-get update && \
RUN dpkg-reconfigure locales && \
locale-gen C.UTF-8 && \
/usr/sbin/update-locale LANG=C.UTF-8
ENV LC_ALL C.UTF-8
ENV LC_ALL=C.UTF-8
RUN apt-get update -qq && \
apt-get upgrade -qq -y && \
@ -39,18 +39,22 @@ RUN apt-get update -qq && \
# <OOW> Install Debian packages
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
COPY addons_debian_requirements.txt /addons_debian_requirements.txt
RUN apt-get update -qq \
&& apt-get install -y git \
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
&& grep -vE '^\s*#|^\s*$' extra_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
&& grep -vE '^\s*#|^\s*$' addons_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
# <OOW> Install Python librairies
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
COPY addons_python_requirements.txt /addons_python_requirements.txt
COPY extra_python_requirements.txt /extra_python_requirements.txt
RUN pip3 install --upgrade pip \
&& python3 -m pip install --no-cache-dir setuptools-scm \
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt \
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt \
&& python3 -m pip install --no-cache-dir -r /addons_python_requirements.txt
# <OOW> Get local user id and set it to the odoo user
ARG LOCAL_USER_ID

View File

@ -13,7 +13,7 @@ RUN apt-get update && \
RUN dpkg-reconfigure locales && \
locale-gen C.UTF-8 && \
/usr/sbin/update-locale LANG=C.UTF-8
ENV LC_ALL C.UTF-8
ENV LC_ALL=C.UTF-8
RUN apt-get update -qq && \
apt-get upgrade -qq -y && \
@ -39,18 +39,22 @@ RUN apt-get update -qq && \
# <OOW> Install Debian packages
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
COPY addons_debian_requirements.txt /addons_debian_requirements.txt
RUN apt-get update -qq \
&& apt-get install -y git \
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
&& grep -vE '^\s*#|^\s*$' extra_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
&& grep -vE '^\s*#|^\s*$' addons_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
# <OOW> Install Python librairies
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
COPY addons_python_requirements.txt /addons_python_requirements.txt
COPY extra_python_requirements.txt /extra_python_requirements.txt
RUN pip3 install --upgrade pip \
&& python3 -m pip install --no-cache-dir setuptools-scm \
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt \
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt \
&& python3 -m pip install --no-cache-dir -r /addons_python_requirements.txt
# <OOW> Get local user id and set it to the odoo user
ARG LOCAL_USER_ID

View File

@ -1,6 +1,9 @@
# <OOW> : Copy of https://github.com/odoo/odoo/blob/13.0/setup/package.dfsrc
FROM debian:buster
RUN sed -i -- 's/security.debian.org/archive.debian.org/g' /etc/apt/**.list
RUN sed -i -- 's/deb.debian.org/archive.debian.org/g' /etc/apt/**.list
RUN apt-get update && \
apt-get install -y locales && \
rm -rf /var/lib/apt/lists/*
@ -9,7 +12,7 @@ RUN apt-get update && \
RUN dpkg-reconfigure locales && \
locale-gen C.UTF-8 && \
/usr/sbin/update-locale LANG=C.UTF-8
ENV LC_ALL C.UTF-8
ENV LC_ALL=C.UTF-8
RUN apt-get update -qq && \
apt-get upgrade -qq -y && \
@ -35,18 +38,22 @@ RUN apt-get update -qq && \
# <OOW> Install Debian packages
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
COPY addons_debian_requirements.txt /addons_debian_requirements.txt
RUN apt-get update -qq \
&& apt-get install -y git \
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
&& grep -vE '^\s*#|^\s*$' extra_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
&& grep -vE '^\s*#|^\s*$' addons_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
# <OOW> Install Python librairies
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
COPY addons_python_requirements.txt /addons_python_requirements.txt
COPY extra_python_requirements.txt /extra_python_requirements.txt
RUN pip3 install --upgrade pip \
&& python3 -m pip install --no-cache-dir setuptools-scm \
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt \
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt \
&& python3 -m pip install --no-cache-dir -r /addons_python_requirements.txt
# <OOW> Get local user id and set it to the odoo user
ARG LOCAL_USER_ID

View File

@ -1,6 +1,9 @@
# <OOW> : Copy of https://github.com/odoo/odoo/blob/14.0/setup/package.dfsrc
FROM debian:buster
RUN sed -i -- 's/security.debian.org/archive.debian.org/g' /etc/apt/**.list
RUN sed -i -- 's/deb.debian.org/archive.debian.org/g' /etc/apt/**.list
RUN apt-get update && \
apt-get install -y locales && \
rm -rf /var/lib/apt/lists/*
@ -9,7 +12,7 @@ RUN apt-get update && \
RUN dpkg-reconfigure locales && \
locale-gen C.UTF-8 && \
/usr/sbin/update-locale LANG=C.UTF-8
ENV LC_ALL C.UTF-8
ENV LC_ALL=C.UTF-8
RUN apt-get update -qq && \
apt-get upgrade -qq -y && \
@ -28,18 +31,22 @@ RUN apt-get update -qq && \
# <OOW> Install Debian packages
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
COPY addons_debian_requirements.txt /addons_debian_requirements.txt
RUN apt-get update -qq \
&& apt-get install -y git \
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
&& grep -vE '^\s*#|^\s*$' extra_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
&& grep -vE '^\s*#|^\s*$' addons_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
# <OOW> Install Python librairies
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
COPY addons_python_requirements.txt /addons_python_requirements.txt
COPY extra_python_requirements.txt /extra_python_requirements.txt
RUN pip3 install --upgrade pip \
&& python3 -m pip install --no-cache-dir setuptools-scm \
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt \
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt \
&& python3 -m pip install --no-cache-dir -r /addons_python_requirements.txt
# <OOW> Get local user id and set it to the odoo user
ARG LOCAL_USER_ID

View File

@ -1,6 +1,9 @@
# <OOW> : Copy of https://github.com/odoo/odoo/blob/15.0/setup/package.dfsrc
FROM debian:buster
RUN sed -i -- 's/security.debian.org/archive.debian.org/g' /etc/apt/**.list
RUN sed -i -- 's/deb.debian.org/archive.debian.org/g' /etc/apt/**.list
RUN apt-get update && \
apt-get install -y locales && \
rm -rf /var/lib/apt/lists/*
@ -9,7 +12,7 @@ RUN apt-get update && \
RUN dpkg-reconfigure locales && \
locale-gen C.UTF-8 && \
/usr/sbin/update-locale LANG=C.UTF-8
ENV LC_ALL C.UTF-8
ENV LC_ALL=C.UTF-8
RUN apt-get update -qq && \
apt-get upgrade -qq -y && \
@ -28,18 +31,22 @@ RUN apt-get update -qq && \
# <OOW> Install Debian packages
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
COPY addons_debian_requirements.txt /addons_debian_requirements.txt
RUN apt-get update -qq \
&& apt-get install -y git \
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
&& grep -vE '^\s*#|^\s*$' extra_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
&& grep -vE '^\s*#|^\s*$' addons_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
# <OOW> Install Python librairies
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
COPY addons_python_requirements.txt /addons_python_requirements.txt
COPY extra_python_requirements.txt /extra_python_requirements.txt
RUN pip3 install --upgrade pip \
&& python3 -m pip install --no-cache-dir setuptools-scm \
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt \
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt \
&& python3 -m pip install --no-cache-dir -r /addons_python_requirements.txt
# <OOW> Get local user id and set it to the odoo user
ARG LOCAL_USER_ID

View File

@ -1,6 +1,9 @@
# <OOW> : Copy of https://github.com/odoo/odoo/blob/16.0/setup/package.dfsrc
FROM debian:buster
RUN sed -i -- 's/security.debian.org/archive.debian.org/g' /etc/apt/**.list
RUN sed -i -- 's/deb.debian.org/archive.debian.org/g' /etc/apt/**.list
RUN apt-get update && \
apt-get install -y locales && \
rm -rf /var/lib/apt/lists/*
@ -9,7 +12,7 @@ RUN apt-get update && \
RUN dpkg-reconfigure locales && \
locale-gen C.UTF-8 && \
/usr/sbin/update-locale LANG=C.UTF-8
ENV LC_ALL C.UTF-8
ENV LC_ALL=C.UTF-8
RUN apt-get update -qq && \
apt-get upgrade -qq -y && \
@ -28,18 +31,22 @@ RUN apt-get update -qq && \
# <OOW> Install Debian packages
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
COPY addons_debian_requirements.txt /addons_debian_requirements.txt
RUN apt-get update -qq \
&& apt-get install -y git \
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
&& grep -vE '^\s*#|^\s*$' extra_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
&& grep -vE '^\s*#|^\s*$' addons_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
# <OOW> Install Python librairies
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
COPY addons_python_requirements.txt /addons_python_requirements.txt
COPY extra_python_requirements.txt /extra_python_requirements.txt
RUN pip3 install --upgrade pip \
&& python3 -m pip install --no-cache-dir setuptools-scm \
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt \
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt \
&& python3 -m pip install --no-cache-dir -r /addons_python_requirements.txt
# <OOW> Get local user id and set it to the odoo user
ARG LOCAL_USER_ID

View File

@ -0,0 +1,54 @@
# <OOW> : Copy of https://github.com/odoo/odoo/blob/17.0/setup/package.dfsrc
FROM debian:bookworm
RUN apt-get update && \
apt-get install -y locales && \
rm -rf /var/lib/apt/lists/*
# Reconfigure locales such that postgresql uses UTF-8 encoding
RUN dpkg-reconfigure locales && \
locale-gen C.UTF-8 && \
/usr/sbin/update-locale LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
RUN apt-get update -qq && \
apt-get upgrade -qq -y && \
apt-get install \
postgresql \
postgresql-server-dev-all \
postgresql-client \
adduser \
libldap2-dev \
libsasl2-dev \
python3-pip \
python3-venv \
python3-wheel \
build-essential \
python3 -y && \
rm -rf /var/lib/apt/lists/*
# <OOW> Install Debian packages
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
COPY addons_debian_requirements.txt /addons_debian_requirements.txt
RUN apt-get update -qq \
&& apt-get install -y git \
&& grep -vE '^\s*#|^\s*$' extra_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
&& grep -vE '^\s*#|^\s*$' addons_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
# <OOW> Install Python librairies
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
COPY addons_python_requirements.txt /addons_python_requirements.txt
COPY extra_python_requirements.txt /extra_python_requirements.txt
RUN pip3 install --upgrade pip --break-system-packages \
&& python3 -m pip install --no-cache-dir setuptools-scm --break-system-packages \
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt --break-system-packages \
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt --break-system-packages \
&& python3 -m pip install --no-cache-dir -r /addons_python_requirements.txt --break-system-packages
# <OOW> Get local user id and set it to the odoo user
ARG LOCAL_USER_ID
RUN useradd --uid $LOCAL_USER_ID --non-unique odoo
USER odoo

View File

@ -0,0 +1,54 @@
# <OOW> : Copy of https://github.com/odoo/odoo/blob/18.0/setup/package.dfsrc
FROM debian:bookworm
RUN apt-get update && \
apt-get install -y locales && \
rm -rf /var/lib/apt/lists/*
# Reconfigure locales such that postgresql uses UTF-8 encoding
RUN dpkg-reconfigure locales && \
locale-gen C.UTF-8 && \
/usr/sbin/update-locale LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
RUN apt-get update -qq && \
apt-get upgrade -qq -y && \
apt-get install \
postgresql \
postgresql-server-dev-all \
postgresql-client \
adduser \
libldap2-dev \
libsasl2-dev \
python3-pip \
python3-venv \
python3-wheel \
build-essential \
python3 -y && \
rm -rf /var/lib/apt/lists/*
# <OOW> Install Debian packages
COPY extra_debian_requirements.txt /extra_debian_requirements.txt
COPY addons_debian_requirements.txt /addons_debian_requirements.txt
RUN apt-get update -qq \
&& apt-get install -y git \
&& grep -vE '^\s*#|^\s*$' extra_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
&& grep -vE '^\s*#|^\s*$' addons_debian_requirements.txt | xargs apt-get install -y --no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
# <OOW> Install Python librairies
COPY ./src/odoo/requirements.txt /odoo_python_requirements.txt
COPY addons_python_requirements.txt /addons_python_requirements.txt
COPY extra_python_requirements.txt /extra_python_requirements.txt
RUN pip3 install --upgrade pip --break-system-packages \
&& python3 -m pip install --no-cache-dir setuptools-scm --break-system-packages \
&& python3 -m pip install --no-cache-dir -r /odoo_python_requirements.txt --break-system-packages \
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt --break-system-packages \
&& python3 -m pip install --no-cache-dir -r /addons_python_requirements.txt --break-system-packages
# <OOW> Get local user id and set it to the odoo user
ARG LOCAL_USER_ID
RUN useradd --uid $LOCAL_USER_ID --non-unique odoo
USER odoo

View File

@ -0,0 +1,8 @@
# Do NOT edit manually. Changes here will be overwritten by the command 'guess-requirement'
{%- for bin_lib, module_list in dependencies.items() %}
# Required by the module(s): {{ ','.join(module_list) }}
{{ bin_lib }}
{%- endfor %}

View File

@ -0,0 +1,8 @@
# Do NOT edit manually. Changes here will be overwritten by the command 'guess-requirement'
{%- for python_lib, module_list in dependencies.items() %}
# Required by the module(s): {{ ','.join(module_list) }}
{{ python_lib }}
{%- endfor %}

View File

@ -7,3 +7,7 @@
# - http or xml port
# - etc.
# Only non standard or special options should be specified here.
[options]
# Disable default memory limit of 2560 MiB
limit_memory_hard = 0

View File

@ -27,7 +27,7 @@ def copydb(ctx, source, dest):
shutil.rmtree(dest_path, ignore_errors=True)
# Copy Filestore
logger.info(f"Copy filestore of '{source}' into '{dest}' folder ...")
logger.info(f"Copy filestore of '{source}' into '{dest}' directory...")
shutil.copytree(source_path, dest_path)

View File

@ -1,3 +1,5 @@
import time
import docker
from loguru import logger
@ -14,7 +16,7 @@ def pull_image(image_name):
def build_image(path, tag, buildargs={}):
logger.debug(
f"Building image named based on {path}/Dockerfile."
" This can take a big while ..."
" This can take a long time..."
)
debug_docker_command = f"docker build {path} --tag {tag}"
for arg_name, arg_value in buildargs.items():
@ -28,11 +30,13 @@ def build_image(path, tag, buildargs={}):
path=str(path),
tag=tag,
buildargs=buildargs,
rm=True,
)
logger.debug("Image build done.")
except docker.errors.BuildError as buildError:
logger.error("\n".join(buildError.build_log))
logger.error("\n".join([str(log) for log in buildError.build_log]))
logger.error("Image build failed.")
raise buildError
return image
@ -110,6 +114,28 @@ def exec_container(container, command):
def kill_container(container_name):
# In some situation, containers.list return
# containers with removal already in progress
# when we call container.remove(), it is raising an
# docker.errors.APIError
# "removal of container xx is already in progress".
# so, we retry a few seconds after
# and raise an exception after five failures.
for i in [1, 5, 10, 60, False]:
try:
_kill_container(container_name)
return
except docker.errors.APIError as e:
if not i:
logger.error(f"Fail to kill {container_name} after 5 retries")
raise e
logger.warning(
f"Fail to kill {container_name}. Retrying in {i} seconds"
)
time.sleep(i)
def _kill_container(container_name):
client = get_docker_client()
try:
@ -131,6 +157,10 @@ def kill_container(container_name):
try:
container.stop()
container.wait()
logger.debug(
"Container %s status is now '%s'."
% (container.name, container.status)
)
if container.status != "removed":
container.remove()
container.wait(condition="removed")

View File

@ -52,7 +52,7 @@ def get_odoo_addons_path(
ctx,
odoo_env_path: Path,
migration_step: dict,
execution_context: str = False,
execution_context: str = None,
) -> str:
"""Return
- addons_path: a list of Path of that contains odoo module
@ -88,14 +88,33 @@ def get_odoo_addons_path(
def is_addons_path(ctx, path: Path, migration_step: dict):
logger.debug(f"Untersuche Pfad: {path}")
for folder in [x for x in path.iterdir() if x.is_dir()]:
logger.debug(f" Untersuche Pfad: {folder}")
if (folder / "__init__.py").exists() and (
folder / get_manifest_name(migration_step)
).exists():
logger.info(f" ✔️ Odoo-Modul gefunden in: {folder}")
return True
return False
#def is_addons_path(ctx, path: Path, migration_step: dict):
# """Prüft, ob im Verzeichnis mindestens ein Odoo-Modul liegt."""
# logger.debug(f"Untersuche Pfad: {path}")
# for folder in path.iterdir():
# if folder.is_dir():
# init_exists = (folder / "__init__.py").exists()
# manifest_path = folder / get_manifest_name(migration_step)
# manifest_exists = manifest_path.exists()
# logger.debug(
# f" Untersuche Unterordner: {folder} | __init__.py: {init_exists}, Manifest: {manifest_path.name}: {manifest_exists}"
# )
# if init_exists and manifest_exists:
# logger.info(f" ✔️ Odoo-Modul gefunden in: {folder}")
# return True
# return False
def get_odoo_env_path(ctx, odoo_version: float) -> Path:
folder_name = "env_%s" % str(odoo_version).rjust(4, "0")
return ctx.obj["src_folder_path"] / folder_name
@ -121,22 +140,22 @@ def get_docker_container_name(ctx, database: str, migration_step: dict) -> str:
)
def generate_odoo_command(
def generate_odoo_command_options(
ctx,
migration_step: dict,
execution_context: str,
database: str,
demo: bool = False,
update: str = False,
init: str = False,
update: str = None,
init: str = None,
stop_after_init: bool = False,
shell: bool = False,
) -> str:
) -> list:
"""
Generate Odoo command options as a list of string to append to any command.
"""
odoo_env_path = get_odoo_env_path(ctx, migration_step["version"])
# Compute 'server_wide_modules'
# For that purpose, read the custom odoo.conf file
# to know if server_wide_modules is defined
custom_odoo_config_file = odoo_env_path / "odoo.conf"
parser = configparser.RawConfigParser()
parser.read(custom_odoo_config_file)
@ -147,10 +166,22 @@ def generate_odoo_command(
migration_step, execution_context
)
# compute 'addons_path'
# Compute 'addons_path'
addons_path_list, empty_addons_path_list = get_odoo_addons_path(
ctx, odoo_env_path, migration_step, execution_context
)
# custom_addons from odoo_version_settings[version]
version = migration_step["version"]
#TODO: check if custom_addons is in ctx.obj['config']
custom_addons = ctx.obj.get("config", {}).get("odoo_version_settings", {}).get(version, {}).get("custom_addons", [])
for path in custom_addons:
logger.info(f"📁 custom_addons: adding path '{path}'")
addons_path_list.append(path)
# Normalize addons path (relative to /odoo_env in container)
addons_path = ",".join(
[str(Path("/odoo_env") / x) for x in addons_path_list]
)
@ -161,62 +192,88 @@ def generate_odoo_command(
" because it doesn't contain any odoo module."
)
# compute 'log_file'
log_file_name = "{}____{}.log".format(
ctx.obj["log_prefix"], migration_step["complete_name"]
# Compute 'log_file'
log_file_name = (
f"{ctx.obj['log_prefix']}____{migration_step['complete_name']}.log"
)
log_file_docker_path = "/env/log/%s" % log_file_name
log_file_docker_path = f"/env/log/{log_file_name}"
database_cmd = database and "--database %s" % database or ""
load_cmd = (
server_wide_modules
and "--load %s" % ",".join(server_wide_modules)
or ""
# Build options string
options = [
"--config=/odoo_env/odoo.conf",
"--data-dir=/env/filestore/",
f"--addons-path={addons_path}",
f"--logfile={log_file_docker_path}",
"--db_host=db",
"--db_port=5432",
"--db_user=odoo",
"--db_password=odoo",
"--workers=0",
f"{'--without-demo=all' if not demo else ''}",
f"{'--load ' + ','.join(server_wide_modules) if server_wide_modules else ''}", # noqa
f"{'--database=' + database if database else ''}",
f"{'--update ' + update if update else ''}",
f"{'--init ' + init if init else ''}",
f"{'--stop-after-init' if stop_after_init else ''}",
]
# Log resolved addons_path
logger.info(f"📦 Final --addons-path: {addons_path}")
# Remove empty strings
return [x for x in options if x]
def generate_odoo_command(
ctx,
migration_step: dict,
execution_context: str,
database: str,
demo: bool = False,
update: str = None,
init: str = None,
stop_after_init: bool = False,
shell: bool = False,
) -> str:
"""
Generate the full Odoo command using options from
generate_odoo_command_options.
"""
options = generate_odoo_command_options(
ctx,
migration_step,
execution_context,
database,
demo,
update,
init,
stop_after_init,
)
update_cmd = update and "--update %s" % update or ""
init_cmd = init and "--init %s" % init or ""
stop_after_init_cmd = stop_after_init and "--stop-after-init" or ""
shell_cmd = shell and "shell" or ""
demo_cmd = not demo and "--without-demo all" or ""
command = (
base_command = (
Path("/odoo_env")
/ Path(get_odoo_folder(migration_step, execution_context))
/ Path(get_odoo_run_command(migration_step))
)
result = (
f" {command}"
f" {shell_cmd}"
f" --config=/odoo_env/odoo.conf"
f" --data-dir=/env/filestore/"
f" --addons-path={addons_path}"
f" --logfile={log_file_docker_path}"
f" --db_host=db"
f" --db_port=5432"
f" --db_user=odoo"
f" --db_password=odoo"
f" --workers=0"
f" {demo_cmd}"
f" {load_cmd}"
f" {database_cmd}"
f" {update_cmd}"
f" {init_cmd}"
f" {stop_after_init_cmd}"
)
return result
options_as_string = " ".join(options)
if shell:
return f"{base_command} shell {options_as_string}"
else:
return f"{base_command} {options_as_string}"
def run_odoo(
ctx,
migration_step: dict,
detached_container: bool = False,
database: str = False,
update: str = False,
init: str = False,
database: str = None,
update: str = None,
init: str = None,
stop_after_init: bool = False,
shell: bool = False,
demo: bool = False,
execution_context: str = False,
execution_context: str = None,
alternative_xml_rpc_port: int = False,
links: dict = {},
publish_ports: bool = False,
@ -268,9 +325,9 @@ def run_container_odoo(
migration_step: dict,
command: str,
detached_container: bool = False,
database: str = False,
database: str = None,
alternative_xml_rpc_port: int = False,
execution_context: str = False,
execution_context: str = None,
links: dict = {},
publish_ports: bool = False,
):
@ -314,7 +371,7 @@ def execute_click_odoo_python_files(
database: str,
migration_step: dict,
python_files: list = [],
execution_context: str = False,
execution_context: str = None,
):
if not python_files:
# Get post-migration python scripts to execute

View File

@ -1,3 +1,4 @@
import ast
import importlib
import os
from functools import total_ordering
@ -110,6 +111,22 @@ class Analysis(object):
for module_version in odoo_module.module_versions.values():
module_version.estimate_workload(ctx)
def get_requirements(self, ctx):
logger.info("Get requirements...")
result = {x: {"python": {}, "bin": {}} for x in self.all_versions}
for odoo_module in self.modules:
for module_version in odoo_module.module_versions.values():
module_result = module_version.get_requirements(ctx)
python_result = result[module_result["version"]]["python"]
module_name = module_result["module_name"]
for python_lib in module_result["python"]:
if python_lib not in python_result:
python_result[python_lib] = [module_name]
else:
python_result[python_lib].append(module_name)
return result
def _generate_module_version_first_version(self, ctx, module_list):
logger.info(f"Analyse version {self.initial_version}. (First version)")
@ -274,22 +291,27 @@ class Analysis(object):
odoo_modules = self.modules
return len(odoo_modules)
def workload_hour_text(self, module_type=False):
def workload(self, module_type, repository):
odoo_modules = self.modules
if module_type:
odoo_modules = [
x
for x in filter(
lambda x: x.module_type == module_type, self.modules
lambda x: x.module_type == module_type, odoo_modules
)
]
if repository:
odoo_modules = [
x
for x in filter(
lambda x: x.repository == repository, odoo_modules
)
]
else:
odoo_modules = self.modules
total = 0
for odoo_module in odoo_modules:
for module_version in list(odoo_module.module_versions.values()):
total += module_version.workload
return "%d h" % (int(round(total / 60)))
return total
@total_ordering
@ -473,7 +495,7 @@ class OdooModuleVersion(object):
"doc",
"description",
]
_exclude_files = ["__openerp__.py", "__manifest__.py"]
_manifest_files = ["__openerp__.py", "__manifest__.py"]
_file_extensions = [".py", ".xml", ".js"]
@ -515,6 +537,63 @@ class OdooModuleVersion(object):
else:
return False
def get_requirements(self, ctx):
result = {
"python": [],
"bin": [],
"module_name": self.odoo_module.name,
"version": self.version,
}
manifest_path = False
for manifest_name in self._manifest_files:
if not self.odoo_module.name or not self.addon_path:
continue
manifest_path = (
self.addon_path / self.odoo_module.name / manifest_name
)
if manifest_path.exists():
break
if not manifest_path or not manifest_path.exists():
return result
with manifest_path.open(mode="r", encoding="utf-8") as f_manifest:
manifest = ast.literal_eval(f_manifest.read())
python_libs = manifest.get("external_dependencies", {}).get(
"python", []
)
bin_libs = manifest.get("external_dependencies", {}).get("bin", [])
result["bin"] = bin_libs
# Handle specific replacement in the setup folder
setup_path = (
self.addon_path / "setup" / self.odoo_module.name / "setup.py"
)
if setup_path.exists():
with setup_path.open(mode="r", encoding="utf-8") as f_setup:
tree = ast.parse(source=f_setup.read())
for node in ast.walk(tree):
if (
node.__class__.__name__ == "Dict"
and "external_dependencies_override"
in [k.value for k in node.keys]
):
python_replacements = ast.literal_eval(
ast.unparse(node)
)["external_dependencies_override"]
break
else:
python_replacements = {}
for k, v in python_replacements.items():
if k in python_libs:
python_libs.remove(k)
result["python"].append(v)
result["python"] += python_libs
return result
def estimate_workload(self, ctx):
settings = ctx.obj["config"]["workload_settings"]
port_minimal_time = settings["port_minimal_time"]
@ -605,7 +684,7 @@ class OdooModuleVersion(object):
if set(Path(relative_path).parts) & set(self._exclude_directories):
continue
for name in files:
if name in self._exclude_files:
if name in self._manifest_files:
continue
filename, file_extension = os.path.splitext(name)
if file_extension in self._file_extensions:

View File

@ -42,29 +42,59 @@ def get_postgres_container(ctx):
# Check if volume exists
try:
client.volumes.get(volume_name)
logger.debug(f"Recovering existing postgres volume: {volume_name}")
logger.debug(f"Recovering existing PostgreSQL volume: {volume_name}")
except docker.errors.NotFound:
logger.info(f"Creating Postgres volume: {volume_name}")
client.volumes.create(volume_name)
command = None
command = "postgres"
postgres_extra_settings = ctx.obj["config"].get("postgres_extra_settings")
if postgres_extra_settings:
command = "postgres"
for key, value in postgres_extra_settings.items():
command += f" -c {key}={value}"
logger.info(f"Launching Postgres Container. (Image {image_name})")
container = run_container(
image_name,
container_name,
command=command,
logger.info(f"Launching PostgreSQL Container. (Image {image_name})")
# base environement variables
environments = {
"POSTGRES_USER": "odoo",
"POSTGRES_PASSWORD": "odoo",
"POSTGRES_DB": "postgres",
"PGDATA": "/var/lib/postgresql/data/pgdata",
},
}
# if postgresql version is >= 14 and odoo <= 12 we need to use md5 for auth
# method and password encryption
try:
postgres_version = float(image_name.split(":")[1])
except ValueError:
raise Exception(
"Unable to extract PostgreSQL version "
f"from image name {image_name}. "
"Define version in the image name is mandatory."
)
try:
odoo_start_version = float(ctx.obj["config"]["odoo_versions"][0])
except ValueError:
raise Exception(
"Unable to extract start odoo version from odoo_versions "
f"{ctx.obj['config']['odoo_versions']}"
)
if odoo_start_version <= 12 and postgres_version >= 14:
environments |= {
"POSTGRES_HOST_AUTH_METHOD": "md5",
"POSTGRES_INITDB_ARGS": "--auth-host=md5",
}
command += " -c password_encryption=md5"
container = run_container(
image_name,
container_name,
command=command,
environments=environments,
volumes={
# Data volume
volume_name: "/var/lib/postgresql/data/pgdata/",
@ -72,6 +102,7 @@ def get_postgres_container(ctx):
ctx.obj["env_folder_path"].absolute(): "/env/",
},
detach=True,
# ports={"5432/tcp": 5432}, # <--- Port-Mapping hinzugefügt
)
# TODO, improve me.
# Postgres container doesn't seems available immediately.
@ -89,8 +120,8 @@ def execute_sql_file(ctx, database, sql_file):
if str(ctx.obj["env_folder_path"]) not in str(sql_file):
raise Exception(
f"The SQL file {sql_file} is not in the"
f" main folder {ctx.obj['env_folder_path']} available"
" in the postgres container."
f" main directory {ctx.obj['env_folder_path']} available"
" in the PostgreSQL container."
)
relative_path = Path(
str(sql_file).replace(str(ctx.obj["env_folder_path"]), ".")
@ -101,7 +132,7 @@ def execute_sql_file(ctx, database, sql_file):
"psql --username=odoo --dbname={database} --file {file_path}"
).format(database=database, file_path=container_path)
logger.info(
f"Executing the script '{relative_path}' in postgres container"
f"Executing the script '{relative_path}' in PostgreSQL container"
f" on database {database}"
)
exec_container(container, command)
@ -132,7 +163,7 @@ def execute_psql_command(
f" {' '.join(psql_args)}"
)
logger.debug(
f"Executing the following command in postgres container\n{command}"
f"Executing the following command in PostgreSQL container\n{command}"
)
docker_result = exec_container(container, command)
return docker_result.output.decode("utf-8")
@ -210,7 +241,7 @@ def chown_to_local_user(ctx, filepath: os.PathLike):
uid=user_uid, filepath=filepath
)
logger.debug(
f"Executing the following command in postgres container:\n{command}"
f"Executing the following command in PostgreSQL container:\n{command}"
)
chown_result = exec_container(container, command)
return chown_result.output.decode("utf8")
@ -246,7 +277,7 @@ def execute_pg_dump(
pg_dump_args=pg_dump_args,
)
logger.debug(
f"Executing the following command in postgres container:\n{command}"
f"Executing the following command in PostgreSQL container:\n{command}"
)
pg_dump_result = exec_container(container, command)

View File

@ -19,7 +19,7 @@ def get_script_folder(ctx, migration_step: dict) -> Path:
def ensure_folder_writable(folder_path: Path):
logger.info(f"Make writable the folder '{folder_path}'")
logger.info(f"Make writable the directory '{folder_path}'")
try:
chmod(["--silent", "--recursive", "o+w", str(folder_path)])
except ProcessExecutionError:
@ -35,9 +35,9 @@ def ensure_folder_exists(
- a log is done at INFO level.
"""
if not folder_path.exists():
cmd = ["--parents", folder_path]
cmd = ["--mode", mode] + cmd
logger.info(f"Creating folder '{folder_path}' ...")
cmd = ["-p", folder_path]
cmd = ["-m", mode] + cmd
logger.info(f"Creating directory '{folder_path}'...")
mkdir(cmd)
if git_ignore_content:
@ -83,15 +83,19 @@ def ensure_file_exists_from_template(
print(output, file=f)
def git_aggregate(folder_path: Path, config_path: Path, jobs: int):
def git_aggregate(folder_path: Path, config_path: Path, jobs: int, env_file: str = ".env"):
# Convert relative env_file path to absolute path before changing directory
if not os.path.isabs(env_file):
env_file = os.path.abspath(env_file)
args = argparse.Namespace(
command="aggregate",
config=str(config_path),
jobs=jobs,
dirmatch=None,
do_push=False,
expand_env=False,
env_file=None,
expand_env=True,
env_file=env_file,
force=True,
)
with working_directory_keeper:
@ -173,3 +177,12 @@ def restore_filestore(
else: # works for "t" and "tgz"
tar = tarfile.open(src_path)
tar.extractall(path=filestore_path)
# If a filestore/filestore/database/filestore directory exists,
# it means that the filestore was in a "filestore" subdirectory
# and we need to move this content to the parent directory.
filestore_subfolder = filestore_path / "filestore"
if filestore_subfolder.exists():
for file in filestore_subfolder.iterdir():
shutil.move(file, filestore_path)
shutil.rmtree(filestore_subfolder)

1035
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,15 @@
[tool.poetry]
[project]
name = "odoo-openupgrade-wizard"
version = "1.0.2"
version = "1.3.1.1"
description = "CLI tool to manage Odoo Major Upgrades"
authors = [
"Sylvain LE GAL <sylvain.legal@grap.coop>",
"Rémy TAYMANS <remy@coopiteasy.be>",
"Simon MAILLARD <simon@ogesta.fr>",
{name = "Sylvain LE GAL", email = "sylvain.legal@grap.coop"},
{name = "Rémy TAYMANS", email = "remy@coopiteasy.be"},
{name = "Simon MAILLARD", email = "simon@ogesta.fr"},
]
maintainers = [
"Sylvain LE GAL <sylvain.legal@grap.coop>",
"Rémy TAYMANS <remy@coopiteasy.be>",
{name = "Sylvain LE GAL", email = "sylvain.legal@grap.coop"},
{name = "Rémy TAYMANS", email = "remy@coopiteasy.be"},
]
readme = "README.md"
repository = "https://gitlab.com/odoo-openupgrade-wizard/odoo-openupgrade-wizard"
@ -23,31 +23,34 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
# Currently poetry 2.0.0 failed to find the following classifier
#"Programming Language :: Python :: 3.13",
"Framework :: Odoo",
]
requires-python = ">=3.9,<4.0"
dependencies = [
"click (>=7.0,<8.0)",
"click-loglevel (>=0.4)",
"docker (>=7.0,<8.0)",
"importlib-resources (>=5.4,<6.0)",
"git-aggregator (>=2.1,<3.0)",
"GitPython (>=3.1,<4.0)",
"jinja2 (>=3.0,<4.0)",
"loguru (>=0.6)",
"odoorpc (>=0.10.1)",
"plumbum (>=1.7,<2.0)",
"pygount (>=1.4,<2.0)",
"pyyaml (>=6.0.0,<7.0.0)",
"single-source (>=0.3)",
]
[project.urls]
Repository = "https://gitlab.com/odoo-openupgrade-wizard/odoo-openupgrade-wizard"
[tool.poetry.scripts]
[project.scripts]
oow = "odoo_openupgrade_wizard.cli.cli:main"
odoo-openupgrade-wizard = "odoo_openupgrade_wizard.cli.cli:main"
[tool.poetry.dependencies]
python = ">=3.9,<4.0.0"
click = "^7.0"
click-loglevel = "^0.4"
docker = "^7.0"
importlib-resources = "^5.4"
git-aggregator = "^2.1"
GitPython = "^3.1"
jinja2 = "^3.0"
loguru = "^0.6"
odoorpc = "^0.10.1"
plumbum = "^1.7"
pygount = "^1.4"
pyyaml = "^6.0.0"
single-source = "^0.3"
[tool.poetry.group.dev.dependencies]
pytest = [

View File

@ -25,7 +25,7 @@ def move_to_test_folder():
if os.getcwd().endswith("tests/data/output"):
return
test_folder_path = Path("tests/data/output")
mkdir([test_folder_path, "--parents"])
mkdir(["-p", test_folder_path])
os.chdir(test_folder_path)

View File

@ -0,0 +1,23 @@
import filecmp
import unittest
from pathlib import Path
from . import cli_runner_invoke, move_to_test_folder
class TestCliGuessRequirement(unittest.TestCase):
def test_cli_guess_requirement(self):
move_to_test_folder()
expected_folder_path = Path("../output_expected").absolute()
cli_runner_invoke(
["guess-requirement", "--extra-modules=sentry"],
)
relative_path = Path("src/env_14.0/addons_python_requirements.txt")
assert filecmp.cmp(
relative_path,
expected_folder_path / relative_path,
)

View File

@ -45,6 +45,38 @@ def test_cli_restoredb(mocker):
# check filestore exists
assert dest_filestore_path.exists()
# check the filestore content is at the right place
assert (dest_filestore_path / "01").exists()
# Check database exists
assert_database(ctx, db_name, "present")
# Delete filestore and database
shutil.rmtree(dest_filestore_path)
ensure_database(ctx, db_name, state="absent")
shutil.copyfile(
pathlib.Path("../restoredb/test_with_nested_filestore_dir.tar.gz"),
filestore_path,
)
cli_runner_invoke(
[
"restoredb",
f"--database={db_name}",
f"--database-path={database_path}",
"--database-format=c",
f"--filestore-path={filestore_path}",
"--filestore-format=tgz",
],
)
# check filestore exists
assert dest_filestore_path.exists()
# check the filestore content is at the right place
assert (dest_filestore_path / "01").exists()
# Check database exists
assert_database(ctx, db_name, "present")

View File

@ -0,0 +1,30 @@
from . import cli_runner_invoke, move_to_test_folder
def test_cli_downgrade_pg_auth_method_for_old_versions():
move_to_test_folder()
cli_runner_invoke(
[
"init",
"--project-name=test-cli-downgrade-auth-method",
"--initial-version=12.0",
"--final-version=13.0",
"--postgresql-version=14",
],
)
move_to_test_folder()
cli_runner_invoke(["get-code"])
cli_runner_invoke(["docker-build", "--versions=12.0"])
db_name = "database_test_cli-downgrade-auth-method__run"
cli_runner_invoke(
[
"run",
"--step=1",
f"--database={db_name}",
"--init-modules=base",
"--stop-after-init",
],
)

View File

@ -28,6 +28,7 @@ migration_steps:
version: 14.0
execution_context: regular
complete_name: step_01__regular__14.0
update: True
- name: 2
version: 15.0
@ -38,6 +39,7 @@ migration_steps:
version: 15.0
execution_context: regular
complete_name: step_03__regular__15.0
update: True
workload_settings:

View File

@ -0,0 +1,4 @@
# Do NOT edit manually. Changes here will be overwritten by the command 'guess-requirement'
# Required by the module(s): sentry
sentry_sdk<=1.9.0

Binary file not shown.