Compare commits

..

1 Commits

Author SHA1 Message Date
Sylvain LE GAL
9b2cd724b5 wip 2024-11-05 17:25:10 +01:00
65 changed files with 961 additions and 2320 deletions

View File

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

4
.markdownlint.rb Normal file
View File

@ -0,0 +1,4 @@
all
# MD033 Inline HTML
# TODO: Tweak elements when https://github.com/markdownlint/markdownlint/issues/118 will be done?
exclude_rule 'MD033'

View File

@ -30,6 +30,14 @@ repos:
rev: "6.1.0"
hooks:
- id: flake8
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: "v0.41.0"
hooks:
- id: markdownlint
args: [ --disable=MD033 ]
# - repo: https://gitlab.com/smop/pre-commit-hooks
# rev: v1.0.0
# hooks:

23
.vscode/launch.json vendored
View File

@ -1,23 +0,0 @@
{
// 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"
}
]
}
]
}

View File

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

View File

@ -6,112 +6,6 @@ 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)
==========================================

View File

@ -1,4 +1,6 @@
# Developers
# Contributors
## Developers
* Sylvain LE GAL, from [GRAP](http://www.grap.coop), since March 2022
* Rémy TAYMANS, from [Coop It Easy](https://coopiteasy.be/), since June 2022
@ -9,11 +11,11 @@
* Hugues DE KEYSER, from [Coop It Easy](https://coopiteasy.be/), since April 2024
* Gabriel PICKENHAYN, since May 2024
* 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
* 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
# Reviewers
## Reviewers
* Sébastien BEAU, from Akretion (https://akretion.com)
* Sébastien BEAU, from [Akretion](https://akretion.com)

View File

@ -1,8 +1,10 @@
# Installation to develop
# Develop
## Basic installation
## Installation to develop
```
### Basic installation
```shell
git clone https://gitlab.com/odoo-openupgrade-wizard/odoo-openupgrade-wizard/
cd odoo-openupgrade-wizard
virtualenv env --python=python3
@ -12,19 +14,20 @@ poetry install
``odoo-openupgrade-wizard`` commands are now available in your virutalenv.
## Advanced installation
### Advanced installation
If you want to use this library without installing anything in your
system, execute the following steps, otherwise, go to 'Installation' part.
1. Run a docker container:
``docker run -it ubuntu:focal``
2. Execute the following commnands
- Run a docker container:
```shell
docker run -it ubuntu:focal
```
- Execute the following commnands
```shell
apt-get update
apt-get install git python3 python3-pip python3-venv
@ -37,40 +40,40 @@ pipx install virtualenv
pipx install poetry
```
# Run tests
## Run tests
## Via pytest (simple)
### Via pytest (simple)
This will run tests only for the current ``python3.X`` version.
(in your virtualenv)
```
```shell
poetry run pytest --cov odoo_openupgrade_wizard --verbosity=2 --exitfirst
```
## Via Tox (advanced)
### Via Tox (advanced)
This will run tests for all the python versions put in the ``tox.ini`` folder.
(in your virtualenv)
```
```shell
tox
```
Note : you should have all the python versions available in your local system.
```
```shell
sudo apt-get install python3.6 python3.6-distutils
sudo apt-get install python3.7 python3.7-distutils
sudo apt-get install python3.8 python3.8-distutils
sudo apt-get install python3.9 python3.9-distutils
```
## Via Gitlab Runner locally
### Via Gitlab Runner locally
```
```shell
# Install tools
pipx install gitlabci-local
@ -78,17 +81,19 @@ pipx install gitlabci-local
gitlabci-local
```
# Debugging
## Debugging
Some docker command could help you when using / developping this tools.
**Enter the postgres container**
To Enter the postgres container, run:
```shell
docker exec -it POSTGRES_CONTAINER_NAME /bin/bash
```
# Contribute
## Contribute
## Provide newsfragments in your merge requests
### Provide newsfragments in your merge requests
If you propose a merge request, please add a newsfragments with it.
@ -115,11 +120,12 @@ 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
### Add python dependencies
If you add new dependencies, you have to:
@ -127,7 +133,7 @@ If you add new dependencies, you have to:
- run the following command in your virtualenv : ``poetry update``
## Release on Gitlab and publish on PyPI
### Release on Gitlab and publish on PyPI
Building, releasing and publishing a new version works with tags.
@ -143,7 +149,7 @@ on gitlab, but they trigger a publication on PyPI.
Before creating a tag, ensure that the version of the program is
updated. To update the program version you can use the command:
```
```shell
poetry version {major,minor,patch}
```
@ -152,14 +158,6 @@ 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.
@ -171,27 +169,26 @@ To see if the publication on PyPI and the release on gitlab were done
correctly, go in Build > Pipelines. You will find a pipeline for the tag
you just created.
## Understanding the library
# Understanding the library
## Tools to understand
### Tools to understand
The library is using many tools. It is recommanded to understand that tools
to contribute to that project:
* Docker (https://www.docker.com/)
* Gitlab CI (https://docs.gitlab.com/ee/ci/quick_start/index.html)
* openupgrade project (https://github.com/oca/openupgrade) and related openupgradelib (https://github.com/oca/openupgradelib)
* poetry (https://python-poetry.org/)
* odoorpc (https://github.com/OCA/odoorpc)
* git-aggregator (https://github.com/acsone/git-aggregator)
- Docker (<https://www.docker.com/>)
- Gitlab CI (<https://docs.gitlab.com/ee/ci/quick_start/index.html>)
- openupgrade project (<https://github.com/oca/openupgrade>)
and related openupgradelib (<https://github.com/oca/openupgradelib>)
- poetry (<https://python-poetry.org/>)
- odoorpc (<https://github.com/OCA/odoorpc>)
- git-aggregator (<https://github.com/acsone/git-aggregator>)
Also this project is inspired by the following tools:
* click-odoo-contrib (https://github.com/acsone/click-odoo-contrib)
- click-odoo-contrib (<https://github.com/acsone/click-odoo-contrib>)
# Dockerfile information
## Dockerfile information
### From version 5 to 7
@ -203,61 +200,68 @@ Try to create dockerfile, based on the odoo official ones fails. Any help welcom
### From version 11.0 to latest version. (Python3)
The Dockerfile of the version 11 to the lastest version of Odoo are written this way :
The Dockerfile of the version 11 to the lastest version of Odoo are written
this way:
- Copy the content of https://github.com/odoo/odoo/blob/ODOO_VERSION/setup/package.dfsrc
- Copy the content of <https://github.com/odoo/odoo/blob/ODOO_VERSION/setup/package.dfsrc>
- remove all the part after the big ``apt-get install``
- install debian package ``git`` to have the possibility to pip install from git url.
- install debian package ``git`` to have the possibility
to pip install from git url.
- install custom debian packages
- install python odoo requirements
- install python ``setuptools-scm`` lib to have the possibility to pip install ``openupgradelib`` from git url.
- install python ``setuptools-scm`` lib to have the possibility
to pip install ``openupgradelib`` from git url.
- install python custom requirements
- makes link between external user and docker odoo user
## Réferences
## References
- how to install gitlab runner locally:
https://docs.gitlab.com/runner/install/linux-manually.html
<https://docs.gitlab.com/runner/install/linux-manually.html>
- Check your CI locally. (French)
https://blog.stephane-robert.info/post/gitlab-valider-ci-yml/
https://blog.callr.tech/building-docker-images-with-gitlab-ci-best-practices/
<https://blog.stephane-robert.info/post/gitlab-valider-ci-yml/>
<https://blog.callr.tech/building-docker-images-with-gitlab-ci-best-practices/>
## Python version settings depending on the debian version
This part can help you if you want to change your autogenerated Dockerfiles.
See (https://github.com/odoo/odoo/blob/ODOO_VERSION/setup/package.dfdebian)
See (<https://github.com/odoo/odoo/blob/ODOO_VERSION/setup/package.dfdebian>).
### debian:wheezy (V7) (for Odoo: 8.0)
- Ubuntu release : 12.04 xxx, 12.10 xxx, 13.04 xxx, 14.10 xxx
- python2.7
- First release : 04/05/2013
- End LTS : May 2018
### debian:jessie (V8) (for Odoo: 9.0, 10.0)
- Ubuntu release : 14.04 trusty, 14.10 utopic, 15.04 vivid, 15.10 wily
- python2.7
- First release : 26/04/2015
- End LTS : June 2020
### debian:stretch (V9) (for Odoo: 11.0, 12.0)
- Ubuntu releases : 16.04 xenial, 16.10 yakkety, 17.04 zesty, 17.10 artful
- python2.7 and python3.5
- First release : 17/06/2017
- End LTS : June 2022
### debian:buster (13.0, 14.0)
- Ubuntu release : 18.04 bionic, 18.10 cosmic, 19.04 disco, 19.10 eoan
- python2.7 and python3.7
- First release : 06/07/2019
- End LTS : Undefined.
## debian:bullseye (15.0, 16.0)
### debian:bullseye (15.0, 16.0)
- Ubuntu release : 20.04 focal, 20.10 groovy, 21.04 hirsute, 21.10 impish
- python3.9
- First release : 14/07/2021

View File

@ -1,69 +0,0 @@
# TODO
* with coop it easy :
- short_help of group decorator ? seems useless...
* add constrains on ``--step`` option.
* revert : set 777 to log and filestore to be able to write on this folder
inside the containers. TODO, ask to coop it easy or commown for better alternative.
* allow to call odoo-bin shell, via : https://github.com/d11wtq/dockerpty
(see https://github.com/docker/docker-py/issues/247)
# List of the series of odoo
# python version is defined, based on the OCA CI.
# https://github.com/OCA/oca-addons-repo-template/blob/master/src/.github/workflows/%7B%25%20if%20ci%20%3D%3D%20'GitHub'%20%25%7Dtest.yml%7B%25%20endif%20%25%7D.jinja
# tips
```
# execute sql request in postgres docker
docker exec db psql --username=odoo --dbname=test_v12 -c "update res_partner set ""email"" = 'bib@bqsdfqsdf.txt';"
```
# TODO Nice To have
- Fix gitlabci-local. For the time being, it is not possible to debug
locally. (there are extra bugs locally that doesn't occures on gitlab,
in ``cli_B_03_run_test.py``...
- add
# Try gitlab runner
curl -LJO "https://gitlab-runner-downloads.s3.amazonaws.com/latest/deb/gitlab-runner_amd64.deb"
sudo dpkg -i gitlab-runner_amd64.deb
(https://docs.gitlab.com/runner/install/linux-manually.html)
# TODO:
- check dynamic user id with
https://github.com/camptocamp/docker-odoo-project/blob/master/bin/docker-entrypoint.sh
in modules.csv.j2 :
# TODO, this value are usefull for test for analyse between 13 and 14.
# move that values in data/extra_script/modules.csv
# and let this template with only 'base' module.
## Without postgres optimization
2022-07-13 19:42
2022-07-13 21:20
Duration : 1:37 (107)
## With postgres optimization
2022-07-13 21:52
2022-07-14 23:11
duration : 1:19 (79)
16%

View File

@ -1,19 +0,0 @@
# 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!

449
README.bk Normal file
View File

@ -0,0 +1,449 @@
<a name="usage"/>
# Usage
**Note:**
the term ``odoo-openupgrade-wizard`` can be replaced by ``oow``
in all the command lines below.
<a name="command-init"/>
## Command: ``init``
```shell
odoo-openupgrade-wizard init\
--initial-version=10.0\
--final-version=12.0\
--project-name=my-customer-10-12\
--extra-repository=OCA/web,OCA/server-tools
```
Initialize a folder to make a migration from a 10.0 and a 12.0 database.
This will generate the following structure :
```
filestore/
log/
2022_03_25__23_12_41__init.log
...
postgres_data/
scripts/
step_1__update__10.0/
pre-migration.sql
post-migration.py
step_2__upgrade__11.0/
...
step_3__upgrade__12.0/
...
step_4__update__12.0/
...
src/
env_10.0/
extra_debian_requirements.txt
Dockerfile
odoo.conf
extra_python_requirements.txt
repos.yml
src/
env_11.0/
...
env_12.0/
...
config.yml
modules.csv
```
- ``config.yml`` is the main configuration file of your project.
- ``modules.csv`` file is an optional file. You can fill it with the list
of your modules installed on your production. The first column of this
file should contain the technical name of the module.
- ``log`` folder will contains all the log of the ``odoo-openupgrade-wizard``
and the logs of the odoo instance that will be executed.
- ``filestore`` folder will contains the filestore of the odoo database(s)
- ``postgres_data`` folder will be used by postgres docker image to store
database.
- ``scripts`` folder contains a folder per migration step. In each step folder:
- ``pre-migration.sql`` can contains extra SQL queries you want to execute
before beginning the step.
- ``post-migration.py`` can contains extra python command to execute
after the execution of the step.
Script will be executed with ``odoo shell`` command. All the ORM is available
via the ``env`` variable.
- ``src`` folder contains a folder per Odoo version. In each environment folder:
- ``repos.yml`` enumerates the list of the repositories to use to run the odoo instance.
The syntax should respect the ``gitaggregate`` command.
(See : https://pypi.org/project/git-aggregator/)
Repo files are pre-generated. You can update them with your custom settings.
(custom branches, extra PRs, git shallow options, etc...)
- ``extra_python_requirements.txt`` enumerates the list of extra python librairies
required to run the odoo instance.
The syntax should respect the ``pip install -r`` command.
(See : https://pip.pypa.io/en/stable/reference/requirements-file-format/)
- ``extra_debian_requirements.txt`` enumerates the list of extra system librairies
required to run the odoo instance.
- ``odoo.conf`` file. Add here extra configuration required for your custom modules.
the classical keys (``db_host``, ``db_port``, etc...) are automatically
autogenerated.
At this step, you should change the autogenerated files.
You can use default files, if you have a very simple odoo instance without custom code,
extra repositories, or dependencies...
**Note:**
- In your repos.yml, preserve ``openupgrade`` and ``server-tools`` repositories
to have all the features of the librairies available.
- In your repos.yml file, the odoo project should be in ``./src/odoo``
and the openupgrade project should be in ``./src/openupgrade/`` folder.
<a name="command-pull-submodule"/>
## Command: ``pull-submodule``
**Prerequites:** init + being in a git repository. (if not, you can simply run ``git init``)
if you already have a repos.yml file on github / gitlab, it can be convenient to
synchronize the repository, instead of copy past the ``repos.yml`` manually.
In that case, you can add extra values, in the ``config.yml`` file in the section
```yaml
odoo_version_settings:
12.0:
repo_url: url_of_the_repo_that_contains_a_repos_yml_file
repo_branch: 12.0
repo_file_path: repos.yml
```
then run following command :
```shell
odoo-openupgrade-wizard pull-submodule
```
<a name="command-get-code"/>
## Command: ``get-code``
**Prerequites:** init
```shell
odoo-openupgrade-wizard get-code
```
This command will simply get all the Odoo code required to run all the steps
for your migration with the ``gitaggregate`` tools.
The code is defined in the ``repos.yml`` of each environment folders. (or in the
directory ``repo_submodule`` if you use ``pull-submodule`` feature.)
**Note**
This step could take a big while !
**Optional arguments**
if you want to update the code of some given versions, you can provide an extra parameter:
```shell
odoo-openupgrade-wizard get-code --versions 10.0,11.0
```
<a name="command-docker-build"/>
## Command: ``docker-build``
**Prerequites:** init + get-code
This will build local docker images that will be used in the following steps.
At this end of this step executing the following command should show a docker image per version.
```shell
docker images --filter "reference=odoo-openupgrade-wizard-*"
```
```
REPOSITORY TAG IMAGE ID CREATED SIZE
odoo-openupgrade-wizard-image---my-customer-10-12---12.0 latest ef664c366208 2 weeks ago 1.39GB
odoo-openupgrade-wizard-image---my-customer-10-12---11.0 latest 24e283fe4ae4 2 weeks ago 1.16GB
odoo-openupgrade-wizard-image---my-customer-10-12---10.0 latest 9d94dce2bd4e 2 weeks ago 924MB
```
**Optional arguments**
- if you want to (re)build an image for some given versions, you can provide
an extra parameter: ``--versions 10.0,12.0``
**Note**
- This step could take a big while also !
<a name="command-run"/>
## Command: ``run``
**Prerequites:** init + get-code + build
```shell
odoo-openupgrade-wizard run\
--step 1\
--database DB_NAME
```
Run an Odoo instance with the environment defined by the step argument.
The database will be created, if it doesn't exists.
if ``stop-after-init`` is disabled, the odoo instance will be available
at your host, at the following url : http://localhost:9069
(Port depends on your ``host_odoo_xmlrpc_port`` setting of your ``config.yml`` file)
**Optional arguments**
- You can add ``--init-modules=purchase,sale`` to install modules.
- You can add ``stop-after-init`` flag to turn off the process at the end
of the installation.
<a name="command-install-from-csv"/>
## Command: ``install-from-csv``
**Prerequites:** init + get-code + build
```shell
odoo-openupgrade-wizard install-from-csv\
--database DB_NAME
```
Install the list of the modules defined in your ``modules.csv`` files on the
given database.
The database will be created, if it doesn't exists.
To get a correct ``modules.csv`` file, the following query can be used:
```shell
psql -c "copy (select name, shortdesc from ir_module_module where state = 'installed' order by 1) to stdout csv" coopiteasy
```
<a name="command-upgrade"/>
## Command: ``upgrade``
**Prerequites:** init + get-code + build
```shell
odoo-openupgrade-wizard upgrade\
--database DB_NAME
```
Realize an upgrade of the database from the initial version to
the final version, following the different steps.
For each step, it will :
1. Execute the ``pre-migration.sql`` of the step.
2. Realize an "update all" (in an upgrade or update context)
3. Execute the scripts via XML-RPC (via ``odoorpc``) defined in
the ``post-migration.py`` file.
**Optional arguments**
- You can add ``--first-step=2`` to start at the second step.
- You can add ``--last-step=3`` to end at the third step.
<a name="command-generate-module-analysis"/>
## Command: ``generate-module-analysis``
**Prerequites:** init + get-code + build
```shell
odoo-openupgrade-wizard generate-module-analysis\
--database DB_NAME
--step 2
--modules MODULE_LIST
```
Realize an analyze between the target version (in parameter via the step argument)
and the previous version. It will generate analysis_file.txt files present
in OpenUpgrade project.
You can also use this fonction to analyze differences for custom / OCA modules
between several versions, in case of refactoring.
<a name="command-estimate-workload"/>
## Command: ``estimate-workload``
**Prerequites:** init + get-code
```shell
odoo-openupgrade-wizard estimate-workload
```
Generate an HTML file name ``analysis.html`` with all the information regarding
the work to do for the migration.
- checks that the modules are present in each version. (by managing the
renaming or merging of modules)
- check that the analysis and migration have been done for the official
modules present in odoo/odoo
<a name="command-psql"/>
## Command: ``psql``
**Prerequites:** init
```shell
odoo-openupgrade-wizard psql
--database DB_NAME
--command "SQL_REQUEST"
```
Execute an SQL Request on the target database.
**Optional arguments**
- If no ``database`` is provided, default ``postgres`` database will be used. exemple:
```shell
odoo-openupgrade-wizard psql --command "\l";
```
Result:
```
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
------------+-------+----------+------------+------------+-------------------
postgres | odoo | UTF8 | en_US.utf8 | en_US.utf8 |
template0 | odoo | UTF8 | en_US.utf8 | en_US.utf8 | =c/odoo +
| | | | | odoo=CTc/odoo
template1 | odoo | UTF8 | en_US.utf8 | en_US.utf8 | =c/odoo +
| | | | | odoo=CTc/odoo
test_psql | odoo | UTF8 | en_US.utf8 | en_US.utf8 |
```
- if you execute request that return long result, you can choose to select ``pager`` or ``-no-pager``
option to display the result via the click function ``echo_via_pager``.
(see : https://click.palletsprojects.com/en/8.1.x/utils/#pager-support)
Note : Pager is enabled by default.
- you can pass extra psql arguments inline.
```shell
odoo-openupgrade-wizard psql
--database=test_psql
--command "select id, name from res_partner where name ilike '%admin%';"
-H
```
Result:
```html
<table border="1">
<tr>
<th align="center">id</th>
<th align="center">name</th>
</tr>
<tr valign="top">
<td align="right">3</td>
<td align="left">Administrator</td>
</tr>
</table>
<p>(1 row)<br />
</p>
```
See all the options here https://www.postgresql.org/docs/current/app-psql.html
<a name="command-copydb"/>
## Command: ``copydb``
**Prerequites:** init
```shell
odoo-openupgrade-wizard copydb
--source DB_NAME
--dest NEW_DB_NAME
```
Create an Odoo database by copying an existing one.
This script copies using postgres CREATEDB WITH TEMPLATE. It also copies
the filestore.
<a name="command-dropdb"/>
## Command: ``dropdb``
**Prerequites:** init
```shell
odoo-openupgrade-wizard dropdb
--database DB_NAME
```
Delete an Odoo database and its filestore.
This command will always success even if DB_NAME does not exists.
<a name="command-dumpdb"/>
## Command: ``dumpdb``
**Prerequites:** init
```shell
odoo-openupgrade-wizard dumpdb
--database DB_NAME
--database-path DATABASE_PATH
--filestore-path FILESTORE_PATH
```
Dump the database DB_NAME to DATABASE_PATH and export the filestore
related to DB_NAME into FILESTORE_PATH. To choose the format of the
backup files look at the `--database-format` and `--filestore-format`.
*WARNING*: DATABASE_PATH should be a sub directory of the project path
in orter to have the postgresql container able to write the dump file.
For example, the project path is `/path/to/myproject` (where you run the
`init` command), then DATABASE_PATH can be any of the subdirectory of
`/path/to/myproject`.
**Optional arguments**
- To chose the database format use `--database-format`. Format can be
one of the following:
- `p` for plain sql text
- `c` for custom compressed backup of `pg_dump`
- `d` for directory structure
- `t` for a tar version of the directory structure
See also https://www.postgresql.org/docs/current/app-pgdump.html
The default database format is `c`.
- To chose the filestore format use `--filestore-format`. Format can be
one of the following:
- `d` copy of the directory structure
- `t` tar version of the directory structure (not compressed)
- `tgz` tar version of the directory structure compressed with gzip.
The default filestore format is `tgz`.
- By default, if database file or filestore file already exists, the
command will fail, preserving the existing dump. If you need to
overwrite the existing files, the `--force` option can be used.

1060
README.md

File diff suppressed because it is too large Load Diff

View File

@ -1,45 +0,0 @@
# Python Version
* py310 is not available, due to dependencies to ``odoorpc`` that raise an error :
``ERROR tests/cli_A_init_test.py - AttributeError: module 'collections' has no attribute 'MutableMapping'``
Follow bug : https://stackoverflow.com/questions/69512672/getting-attributeerror-module-collections-has-no-attribute-mutablemapping-w
# openUpgradelib Versions
* ``openupgradelib`` requires a new feature psycopg2.sql since
(21 Aug 2019)
https://github.com/OCA/openupgradelib/commit/7408580e4469ba4b0cabb923da7facd71567a2fb
so we pin openupgradelib==2.0.0 (21 Jul 2018)
The python version in the Odoo:12 docker image is : ``Python 3.5.3 (default, Apr 5 2021, 09:00:41)`` that is very old.
- https://github.com/OCA/openupgradelib/issues/248
- https://github.com/OCA/openupgradelib/issues/288
- https://github.com/OCA/openupgradelib.git@ed01555b8ae20f66b3af178c8ecaf6edd110ce75#egg=openupgradelib
TODO : Fix via another way (other way than pining ``openuppgradelib`` version) the problem of old odoo versions. (it makes the upgrade failing for old revision (V8, etc...))
# Gitlab-CI
* for the time being, Features requiring ``odoorpc`` are failing in gitlab-CI.
Tests are working locally but there is a network problem. For that reason, tests witch names
begins by ``cli_2`` like (``cli_20_install_from_csv_test.py``) are disabled in ``.gitlab-ci.yml``.
TODO : work with Pierrick Brun, to run gitlab-runner on Akretion CI (without docker), to see if it is
fixing the problem.
# Features Work In Progress
* Add a tools to analyze workload.
# Possible Improvments
* select ``without-demo all`` depending on if the database
is created or not (and if current database contains demo data, checking if base.user_demo exists ?)
# Other points not in the scope of GRAP work
* Allow to use custom docker images.
* Check if there are default values for containers, limiting ressources.

1
newsfragments/add-17.0 Normal file
View File

@ -0,0 +1 @@
Support 17.0 serie.

1
newsfragments/add-18.0 Normal file
View File

@ -0,0 +1 @@
Support 18.0 serie.

View File

@ -1,10 +1,3 @@
#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
@ -31,7 +24,6 @@ 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
@ -56,9 +48,9 @@ DEFAULT_MODULES_FILE = "modules.csv"
writable=True,
resolve_path=True,
),
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 (./).",
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 (./).",
)
@click.option(
"-c",
@ -69,7 +61,7 @@ DEFAULT_MODULES_FILE = "modules.csv"
),
help=(
f"Configuration file to use. By default, a file named "
f'"{DEFAULT_CONFIG_FILE}" in the environment directory will be used.'
f'"{DEFAULT_CONFIG_FILE}" in the environment folder will be used.'
),
)
@click.option(
@ -80,7 +72,7 @@ DEFAULT_MODULES_FILE = "modules.csv"
),
help=(
f"Modules file to use. By default, a file named "
f'"{DEFAULT_MODULES_FILE}" in the environment directory will be used.'
f'"{DEFAULT_MODULES_FILE}" in the environment folder will be used.'
),
)
@click.option(
@ -88,28 +80,22 @@ DEFAULT_MODULES_FILE = "modules.csv"
type=click.Path(
exists=True, file_okay=False, writable=True, resolve_path=True
),
help="Directory that contains the Odoo filestore of the database(s) to "
"migrate. Leave empty to use the subdirectory 'filestore' of the "
"environment directory.",
help="Folder that contains the Odoo filestore of the database(s)"
" to migrate. Let empty to use the subfolder 'filestore' of the"
" environment folder.",
)
@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.
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`
"""
Provides a command set to perform odoo Community Edition migrations.
"""
date_begin = datetime.datetime.now()
logger.remove()
logger.add(sys.stderr, level=log_level)
logger.debug(f"Beginning script '{ctx.invoked_subcommand}'...")
logger.debug(f"Beginning script '{ctx.invoked_subcommand}' ...")
if not isinstance(ctx.obj, dict):
ctx.obj = {}
@ -124,6 +110,16 @@ 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:
@ -134,38 +130,24 @@ 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)
@ -176,7 +158,6 @@ 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,20 +10,17 @@ from odoo_openupgrade_wizard.tools import (
"-s",
"--source",
type=str,
help="Name of the source database to copy.",
help="Name of the database to copy",
)
@click.option(
"-d",
"--dest",
type=str,
help="Name of the destination database to create.",
help="Name of the new database",
)
@click.pass_context
def copydb(ctx, source, dest):
"""Create a new Odoo database by copying another.
This command duplicates both the PostgreSQL database and its associated
filestore.
"""Create an Odoo database by copying an existing one.
it will copy the postgres database and the filestore.
"""
click_odoo_contrib.copydb(ctx, source, dest)

View File

@ -17,16 +17,11 @@ from odoo_openupgrade_wizard.tools.tools_system import get_local_user_id
@versions_options
@click.pass_context
def docker_build(ctx, versions):
"""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.
"""
"""Build Odoo Docker Images and pull Postgres image"""
# 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"])
@ -37,16 +32,16 @@ def docker_build(ctx, versions):
)
if not odoo_requirement_file_path.exists():
logger.error(
"Cannot build Odoo Docker image for version {odoo_version}, "
"Building Odoo docker image for version {odoo_version}, "
"because file {odoo_requirement_file_path} cannot be found. "
"Have you run the get-code command?",
"Have your 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,34 +17,33 @@ from odoo_openupgrade_wizard.tools.tools_system import dump_filestore
"--database-path",
type=click.Path(writable=True, resolve_path=True),
required=True,
help="Destination path for the database dump relative to the project "
"directory.",
help="Path to the database dump relative project folder.",
)
@click.option(
"--database-format",
type=click.Choice(("p", "c", "d", "t")),
default="c",
help="Database format (see pg_dump options): plain SQL (p), "
"custom format compressed (c), directory (d), or tar file (t).",
help="Database format (see pg_dump options): plain sql text (p), "
"custom format compressed (c), directory (d), tar file (t).",
)
@click.option(
"--filestore-path",
type=click.Path(writable=True, resolve_path=True),
required=True,
help="Destination path for the filestore backup.",
help="Path to the filestore backup.",
)
@click.option(
"--filestore-format",
type=click.Choice(("d", "t", "tgz")),
default="tgz",
help="Filestore format: directory (d), tar file (t), "
"or tar file compressed with gzip (tgz)",
"tar file compressed with gzip (tgz)",
)
@click.option(
"--force",
is_flag=True,
default=False,
help="Overwrite files if they already exist.",
help="Overwrite file if they already exists.",
)
@click.pass_context
def dumpdb(
@ -56,14 +55,7 @@ def dumpdb(
filestore_format,
force,
):
"""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.
"""
"""Create an dump of an Odoo database and its filestore."""
database_path = pathlib.Path(database_path)
filestore_path = pathlib.Path(filestore_path)
@ -75,7 +67,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,43 +17,35 @@ 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="Comma-separated list of modules to analyze. If not set, "
"modules.csv will be used. Example: 'account,product,base'.",
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'",
)
@click.option(
"--time-unit",
type=click.Choice(["hour", "minute", "separator"]),
default="separator",
show_default=True,
help="Format to use for displaying time in the report. "
help="Select unit to display time in the report. "
"*separator* display time as `HHH<sep>MM`, "
"*hour* display time as decimal hour, "
"*min* display time as minutes (rounded).",
"*min* display time as minute (rounded).",
)
@click.option(
"--time-separator",
default=":",
help="Character to use as a separator in time output. "
"Used only if --time-unit=separator. Default is ':' (e.g. HHH:MM).",
help="Specify time separator, if time-unit is separator. "
"Default to `:` (it will produce time like this 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,29 +22,11 @@ from odoo_openupgrade_wizard.tools.tools_odoo import (
exists=True,
dir_okay=False,
),
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.""",
help="List of python files that will be executed, replacing the default"
" scripts placed in the migration step folder.",
)
@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,21 +22,11 @@ from odoo_openupgrade_wizard.tools.tools_postgres import (
exists=True,
dir_okay=False,
),
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.",
help="List of SQL files that will be executed, replacing the default"
" scripts placed in the migration step folder.",
)
@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,24 +28,11 @@ from odoo_openupgrade_wizard.tools.tools_system import ensure_folder_writable
"-m",
"--modules",
type=str,
help="Comma-separated list of modules to analyse."
" Leave empty to analyse all the Odoo modules.",
help="Coma-separated list of modules to analysis."
" Let 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,15 +19,11 @@ 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 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).
"""
"""Get code by running gitaggregate command for each version"""
for odoo_version in get_odoo_versions_from_options(ctx, versions):
folder_path = get_odoo_env_path(ctx, odoo_version)

View File

@ -1,61 +0,0 @@
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,44 +19,42 @@ from odoo_openupgrade_wizard.tools.tools_system import (
required=True,
prompt=True,
type=str,
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.",
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.",
)
@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. 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.""",
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.",
)
@click.option(
"--extra-repository",
"extra_repository_list",
# TODO, add a callback to check the quality of the argument
help="Comma-separated extra repositories to use in the Odoo environment."
"Example: 'OCA/web,OCA/server-tools,GRAP/grap-odoo-incubator'",
help="Coma separated extra repositories to use in the odoo environment."
"Ex: 'OCA/web,OCA/server-tools,GRAP/grap-odoo-incubator'",
)
@click.pass_context
def init(
@ -67,10 +65,8 @@ def init(
postgresql_version,
extra_repository_list,
):
"""Initialize the OOW project environment.
This command sets up the project folder structure, configuration
files, and default templates needed to begin an Odoo migration.
"""Initialize OOW Environment based on the initial and
the final version of Odoo you want to migrate.
"""
# Handle arguments
@ -156,30 +152,18 @@ def init(
path_version = get_odoo_env_path(ctx, odoo_version)
ensure_folder_exists(path_version)
# Create python requirements files
# Create python requirements file
ensure_file_exists_from_template(
path_version / Path("extra_python_requirements.txt"),
"odoo/extra_python_requirements.txt.j2",
)
ensure_file_exists_from_template(
path_version / Path("addons_python_requirements.txt"),
"odoo/addons_python_requirements.txt.j2",
dependencies={},
)
# Create debian requirements files
# Create debian requirements file
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,12 +20,6 @@ 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")
@ -36,7 +30,7 @@ def install_from_csv(ctx, database, with_demo):
logger.debug(module_names)
try:
logger.info(f"Install 'base' module on {database} database...")
logger.info(f"Install 'base' module on {database} database ...")
run_odoo(
ctx,
migration_step,
@ -64,7 +58,7 @@ def install_from_csv(ctx, database, with_demo):
raise Exception(
f"Unable to find a country, based on the"
f" code {odoo_default_company['country_code']}."
f" Countries found:"
f" Countries found :"
f" {', '.join([x.name for x in countries])}"
)
vals = {

View File

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

View File

@ -6,29 +6,14 @@ 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",
help="SQL command to execute inside the container.",
)
@click.option(
"--pager/--no-pager",
default=True,
help="Enable or disable pager when displaying output.",
)
@click.option("-c", "--command", "request")
@click.option("--pager/--no-pager", default=True)
@click.argument("psql_args", nargs=-1, type=click.UNPROCESSED)
@click.pass_context
def psql(ctx, request, database, pager, psql_args):
"""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.
"""Run psql in the postgres container. Fill any parameters of psql
as PSQLARGS.
"""
result = execute_psql_command(ctx, request, database, psql_args)
if pager:
click.echo_via_pager(result)

View File

@ -13,12 +13,8 @@ from odoo_openupgrade_wizard.tools.tools_system import execute_check_output
@versions_options
@click.pass_context
def pull_submodule(ctx, versions):
"""Pull the repos.yml file from a Git repository.
"""Pull submodule that contains repos.yml file, if define in config.yml"""
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 {}
@ -26,7 +22,7 @@ def pull_submodule(ctx, versions):
if version_cfg.get("repo_url"):
logger.info(
f"Pull repos.yml from git repository"
f" for version {odoo_version}..."
f" for version {odoo_version} ..."
)
submodule_path = (
get_odoo_env_path(ctx, odoo_version) / "repo_submodule"
@ -57,5 +53,5 @@ def pull_submodule(ctx, versions):
else:
logger.warning(
f"No submodule configuration found"
f" for version {odoo_version}..."
f" for version {odoo_version} ..."
)

View File

@ -12,30 +12,31 @@ from odoo_openupgrade_wizard.tools.tools_system import restore_filestore
@click.option(
"--database-path",
required=True,
type=click.Path(readable=True, resolve_path=True, exists=True),
help="Path to the database dump (inside the environment folder).",
type=click.Path(readable=True, resolve_path=True),
help="Path to the database dump relative project folder.",
)
@click.option(
"--database-format",
required=True,
type=click.Choice(("c", "d", "t", "p")),
default="c",
help="Format of the database dump: custom (c), directory (d), tar (t), "
"or plain SQL (p).",
help="Database format (see pg_dump options): "
"custom format compressed (c), directory (d), tar file (t),"
" plain sql text (p).",
)
@click.option(
"--filestore-path",
required=True,
type=click.Path(readable=True, resolve_path=True, exists=True),
help="Path to the filestore backup (inside the environment folder).",
type=click.Path(readable=True, resolve_path=True),
help="Path to the filestore backup.",
)
@click.option(
"--filestore-format",
required=True,
type=click.Choice(("d", "t", "tgz")),
default="tgz",
help="Format of the filestore: directory (d), tar (t), or gzip-compressed "
"tar (tgz).",
help="Filestore format: directory (d), tar file (t), "
"tar file compressed with gzip (tgz)",
)
@click.pass_context
def restoredb(
@ -46,13 +47,7 @@ def restoredb(
filestore_path,
filestore_format,
):
"""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.
"""
"""Restore an Odoo database and associated filestore."""
database_path = Path(database_path)
filestore_path = Path(filestore_path)
@ -62,9 +57,8 @@ 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 it."
"postgresql to read to 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."
" Leave empty to use the default execution of the migration step.",
" Let empty to use the defaut execution of the migration step.",
)
@click.pass_context
def run(
@ -54,14 +54,6 @@ 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:
@ -82,7 +74,7 @@ def run(
"Odoo is available on your host at http://localhost:"
f"{ctx.obj['config']['odoo_host_xmlrpc_port']}"
)
input("Press 'Enter' to kill the odoo container and exit...")
input("Press 'Enter' to kill the odoo container and exit ...")
except (KeyboardInterrupt, SystemExit):
logger.info("Received Keyboard Interrupt or System Exiting...")
finally:

View File

@ -25,45 +25,23 @@ 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,
migration_step,
database=database,
detached_container=False,
update="all",
stop_after_init=True,
demo=with_demo,
)
except (KeyboardInterrupt, SystemExit):
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'"
try:
run_odoo(
ctx,
migration_step,
database=database,
detached_container=False,
update="all",
stop_after_init=True,
demo=with_demo,
)
else:
logger.info(
"Skip update=all for"
f" step {migration_step.get('complete_name')}"
)
except (KeyboardInterrupt, SystemExit):
logger.info("Received Keyboard Interrupt or System Exiting...")
finally:
kill_odoo(ctx, database, migration_step)
execute_click_odoo_python_files(ctx, database, migration_step)

View File

@ -51,7 +51,7 @@ def get_odoo_run_command(migration_step: dict) -> str:
def get_odoo_folder(
migration_step: dict, execution_context: str = None
migration_step: dict, execution_context: str = False
) -> str:
"""return the main odoo folder, depending on the migration step.
(./src/odoo, ./src/openupgrade, ...)"""
@ -100,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 = None
migration_step: dict, execution_context: str = False
) -> list:
"""return a list of modules to load, depending on the migration step."""
if (
@ -125,8 +125,8 @@ def get_upgrade_analysis_module(migration_step: dict) -> str:
def generate_records(odoo_instance, migration_step: dict):
logger.info(
"Generate Records in version %s..."
" (This may take a while)" % (migration_step["version"])
"Generate Records in version %s ..."
" (It can take a while)" % (migration_step["version"])
)
if migration_step["version"] < 14.0:
wizard = odoo_instance.browse_by_create(
@ -165,7 +165,7 @@ def generate_analysis_files(
):
logger.info(
"Generate analysis files for"
" the modules installed on %s..." % (initial_database)
" the modules installed on %s ..." % (initial_database)
)
proxy_vals = {
"name": "Proxy to Previous version",
@ -176,12 +176,12 @@ def generate_analysis_files(
"password": "admin",
}
if final_step["version"] < 14.0:
logger.info("> Create proxy...")
logger.info("> Create proxy ...")
proxy = final_odoo_instance.browse_by_create(
"openupgrade.comparison.config", proxy_vals
)
logger.info("> Create wizard...")
logger.info("> Create wizard ...")
wizard = final_odoo_instance.browse_by_create(
"openupgrade.analysis.wizard",
{
@ -189,16 +189,16 @@ def generate_analysis_files(
"write_files": True,
},
)
logger.info("> Launch analysis. This can take a while...")
logger.info("> Launch analysis. This can take a while ...")
wizard.get_communication()
else:
logger.info("> Create proxy...")
logger.info("> Create proxy ...")
proxy = final_odoo_instance.browse_by_create(
"upgrade.comparison.config", proxy_vals
)
logger.info("> Create wizard...")
logger.info("> Create wizard ...")
analysis = final_odoo_instance.browse_by_create(
"upgrade.analysis",
{
@ -206,7 +206,7 @@ def generate_analysis_files(
},
)
logger.info("> Launch analysis. This can take a while...")
logger.info("> Launch analysis. This can take a while ...")
analysis.analyze()
@ -267,6 +267,6 @@ def get_openupgrade_analysis_files(
module_name = file.parent.parent.name
result[module_name] = file
logger.debug(
"Version %s: %d analysis files found." % (version, len(result))
"Version %s : %d analysis files found." % (version, len(result))
)
return result

View File

@ -1,23 +1,4 @@
<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%">
@ -37,14 +18,6 @@
<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>
@ -60,31 +33,29 @@
<tr>
<td>Odoo</td>
<td>{{ analysis.get_module_qty('odoo') }}</td>
<td>{{ time_to_text(analysis.workload('odoo', False)) }}</td>
<td>{{ analysis.workload_hour_text('odoo') }}</td>
</tr>
<tr>
<td>OCA</td>
<td>{{ analysis.get_module_qty('oca') }}</td>
<td>{{ time_to_text(analysis.workload('oca', False)) }}</td>
<td>{{ analysis.workload_hour_text('oca') }}</td>
</tr>
<tr>
<td>Custom</td>
<td>{{ analysis.get_module_qty('custom') }}</td>
<td>{{ time_to_text(analysis.workload('custom', False)) }}</td>
<td>{{ analysis.workload_hour_text('custom') }}</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>{{ time_to_text(analysis.workload(False, False)) }}</td>
<td>{{ analysis.workload_hour_text() }}</td>
</tr>
</tfood>
</table>
@ -95,100 +66,116 @@
<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='') %}
{% set ns = namespace(
current_repository='',
current_module_type='',
) %}
{% for odoo_module in analysis.modules %}
{%- for odoo_module in analysis.modules %}
{%- if (ns.current_module_type != odoo_module.module_type) %}
{%- set ns.current_module_type = odoo_module.module_type %}
<!-- ---------------------- -->
<!-- Handle New Module Type -->
<!-- ---------------------- -->
<!-- ------------------------------------------------ -->
<!-- Handle New Module Type {{ns.current_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 %}
<tr>
<th colspan="{{2 + ctx.obj['config']['odoo_versions']|length}}">
<h3>{{ odoo_module.module_type}}</h3>
{{ ns.current_module_type}}
</th>
<tr>
{%- endif %}
{% endif %}
{%- if ns.current_repository != odoo_module.repository %}
{%- set ns.current_repository = odoo_module.repository %}
{%- set repository_workload = analysis.workload(False, odoo_module.repository) %}
<!-- -------------------- -->
<!-- Handle New Repository-->
<!-- -------------------- -->
<!-- ---------------------------------------------- -->
<!-- Handle New Repository {{ns.current_repository}}-->
<!-- ---------------------------------------------- -->
{% if ns.current_repository != odoo_module.repository %}
{% set ns.current_repository = odoo_module.repository %}
{%- if ns.current_repository %}
<tr class="{{repository_workload == 0 and 'work_done' or ''}}">
{% if ns.current_repository %}
<tr>
<th colspan="{{2 + ctx.obj['config']['odoo_versions']|length}}">
<h4>{{ odoo_module.repository}}
{% if repository_workload %}
({{ time_to_text(repository_workload) }})
{% endif %}
</h4>
{{ ns.current_repository}}
</th>
<tr>
{%- endif %}
{%- endif %}
{% endif %}
{% endif %}
<tr class="{{odoo_module.workload == 0 and 'work_done' or ''}}">
<!-- -------------------- -->
<!-- Display Module Line -->
<!-- -------------------- -->
<tr>
<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 -%}
<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 -%}
</td>
<td>
{%- if odoo_module.workload -%}
{{time_to_text(odoo_module.workload)}}
{%- endif -%}
{% 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 %}
</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 %}
<td>
{% if odoo_module.workload %}
{{time_to_text(odoo_module.workload)}}
{% 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 %}
<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 -%}
<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;">
<a href="{{module_version.analysis_url()}}" target="_blank">({{ analysis_text}})</a>
</span>
{%- endif %}
{% 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;">
<a href="{{module_version.analysis_url()}}" target="_blank">
({{ analysis_text}})
</a>
</span>
{% endif %}
</td>
{%- else %}
{% else %}
<td style="background-color:gray;">&nbsp;</td>
{%- endif %}
{%- endfor %}
{% endif %}
{% endfor %}
</tr>
{%- endfor %}
{% endfor %}
</tbody>
</table>

View File

@ -31,9 +31,6 @@ 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

@ -39,22 +39,18 @@ 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 \
&& 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 \
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
&& 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 /addons_python_requirements.txt
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt
# <OOW> Get local user id and set it to the odoo user
ARG LOCAL_USER_ID

View File

@ -39,22 +39,18 @@ 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 \
&& 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 \
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
&& 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 /addons_python_requirements.txt
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt
# <OOW> Get local user id and set it to the odoo user
ARG LOCAL_USER_ID

View File

@ -1,9 +1,6 @@
# <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/*
@ -38,22 +35,18 @@ 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 \
&& 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 \
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
&& 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 /addons_python_requirements.txt
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt
# <OOW> Get local user id and set it to the odoo user
ARG LOCAL_USER_ID

View File

@ -1,9 +1,6 @@
# <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/*
@ -31,22 +28,18 @@ 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 \
&& 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 \
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
&& 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 /addons_python_requirements.txt
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt
# <OOW> Get local user id and set it to the odoo user
ARG LOCAL_USER_ID

View File

@ -1,9 +1,6 @@
# <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/*
@ -31,22 +28,18 @@ 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 \
&& 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 \
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
&& 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 /addons_python_requirements.txt
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt
# <OOW> Get local user id and set it to the odoo user
ARG LOCAL_USER_ID

View File

@ -1,9 +1,6 @@
# <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/*
@ -31,22 +28,18 @@ 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 \
&& 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 \
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
&& 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 /addons_python_requirements.txt
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt
# <OOW> Get local user id and set it to the odoo user
ARG LOCAL_USER_ID

View File

@ -29,22 +29,18 @@ 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 \
&& 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 \
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
&& 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
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt --break-system-packages
# <OOW> Get local user id and set it to the odoo user
ARG LOCAL_USER_ID

View File

@ -29,22 +29,18 @@ 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 \
&& 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 \
&& xargs apt-get install -y --no-install-recommends <extra_debian_requirements.txt \
&& 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
&& python3 -m pip install --no-cache-dir -r /extra_python_requirements.txt --break-system-packages
# <OOW> Get local user id and set it to the odoo user
ARG LOCAL_USER_ID

View File

@ -1,8 +0,0 @@
# 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

@ -1,8 +0,0 @@
# 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,7 +7,3 @@
# - 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

@ -1,7 +1,7 @@
import logging
_logger = logging.getLogger(__name__)
_logger.info("Executing post-migration.py script...")
_logger.info("Executing post-migration.py script ...")
env = env # noqa: F821

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}' directory...")
logger.info(f"Copy filestore of '{source}' into '{dest}' folder ...")
shutil.copytree(source_path, dest_path)

View File

@ -16,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 long time..."
" This can take a big while ..."
)
debug_docker_command = f"docker build {path} --tag {tag}"
for arg_name, arg_value in buildargs.items():
@ -30,7 +30,6 @@ 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:
@ -59,7 +58,7 @@ def run_container(
" Did you run 'odoo-openupgrade-wizard docker-build' ?"
)
logger.debug(f"Launching Docker container named {image_name}...")
logger.debug(f"Launching Docker container named {image_name} ...")
debug_docker_command = f"docker run --name {container_name}\\\n"
for k, v in ports.items():
@ -106,8 +105,8 @@ def exec_container(container, command):
if docker_result.exit_code != 0:
raise Exception(
f"The command failed in the container {container.name}.\n"
f"- Command: {command}\n"
f"- Exit Code: {docker_result.exit_code}\n"
f"- Command : {command}\n"
f"- Exit Code : {docker_result.exit_code}\n"
f"- Output: {docker_result.output}"
)
return docker_result

View File

@ -52,7 +52,7 @@ def get_odoo_addons_path(
ctx,
odoo_env_path: Path,
migration_step: dict,
execution_context: str = None,
execution_context: str = False,
) -> str:
"""Return
- addons_path: a list of Path of that contains odoo module
@ -88,33 +88,14 @@ 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
@ -140,22 +121,22 @@ def get_docker_container_name(ctx, database: str, migration_step: dict) -> str:
)
def generate_odoo_command_options(
def generate_odoo_command(
ctx,
migration_step: dict,
execution_context: str,
database: str,
demo: bool = False,
update: str = None,
init: str = None,
update: str = False,
init: str = False,
stop_after_init: bool = False,
) -> list:
"""
Generate Odoo command options as a list of string to append to any command.
"""
shell: bool = False,
) -> str:
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)
@ -166,22 +147,10 @@ def generate_odoo_command_options(
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]
)
@ -192,88 +161,62 @@ def generate_odoo_command_options(
" because it doesn't contain any odoo module."
)
# Compute 'log_file'
log_file_name = (
f"{ctx.obj['log_prefix']}____{migration_step['complete_name']}.log"
# compute 'log_file'
log_file_name = "{}____{}.log".format(
ctx.obj["log_prefix"], migration_step["complete_name"]
)
log_file_docker_path = f"/env/log/{log_file_name}"
log_file_docker_path = "/env/log/%s" % log_file_name
# 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,
database_cmd = database and "--database %s" % database or ""
load_cmd = (
server_wide_modules
and "--load %s" % ",".join(server_wide_modules)
or ""
)
base_command = (
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 = (
Path("/odoo_env")
/ Path(get_odoo_folder(migration_step, execution_context))
/ Path(get_odoo_run_command(migration_step))
)
options_as_string = " ".join(options)
if shell:
return f"{base_command} shell {options_as_string}"
else:
return f"{base_command} {options_as_string}"
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
def run_odoo(
ctx,
migration_step: dict,
detached_container: bool = False,
database: str = None,
update: str = None,
init: str = None,
database: str = False,
update: str = False,
init: str = False,
stop_after_init: bool = False,
shell: bool = False,
demo: bool = False,
execution_context: str = None,
execution_context: str = False,
alternative_xml_rpc_port: int = False,
links: dict = {},
publish_ports: bool = False,
@ -290,8 +233,8 @@ def run_odoo(
or migration_step["execution_context"],
demo_text=demo and "enabled" or "disabled",
stop_text=stop_after_init and " (stop-after-init)" or "",
init_text=init and " (Init: %s)" % init or "",
update_text=update and " (Update: %s)" % update or "",
init_text=init and " (Init : %s)" % init or "",
update_text=update and " (Update : %s)" % update or "",
)
)
@ -325,9 +268,9 @@ def run_container_odoo(
migration_step: dict,
command: str,
detached_container: bool = False,
database: str = None,
database: str = False,
alternative_xml_rpc_port: int = False,
execution_context: str = None,
execution_context: str = False,
links: dict = {},
publish_ports: bool = False,
):
@ -371,7 +314,7 @@ def execute_click_odoo_python_files(
database: str,
migration_step: dict,
python_files: list = [],
execution_context: str = None,
execution_context: str = False,
):
if not python_files:
# Get post-migration python scripts to execute
@ -397,7 +340,7 @@ def execute_click_odoo_python_files(
try:
logger.info(
f"Step {migration_step['complete_name']}."
f" Executing script {python_file}..."
f" Executing script {python_file} ..."
)
run_container_odoo(
ctx,
@ -419,7 +362,7 @@ def execute_click_odoo_python_files(
def get_odoo_modules_from_csv(module_file_path: Path) -> list:
logger.debug(f"Reading '{module_file_path}' file...")
logger.debug(f"Reading '{module_file_path}' file ...")
module_names = []
csvfile = open(module_file_path, "r")
spamreader = csv.reader(csvfile, delimiter=",", quotechar='"')

View File

@ -39,7 +39,7 @@ class OdooInstance:
logger.debug(
f"{x}/{_ODOO_RPC_MAX_TRY}"
" Unable to connect to the server."
" Retrying in 1 second..."
" Retrying in 1 second ..."
)
time.sleep(1)
else:
@ -96,7 +96,7 @@ class OdooInstance:
while installed is False:
try_qty += 1
try_qty_text = f" (try #{try_qty})" if try_qty != 1 else ""
logger.info(f"{log_prefix}': Installing... {try_qty_text}")
logger.info(f"{log_prefix}': Installing ...{try_qty_text}")
try:
module.button_immediate_install()
installed = True

View File

@ -1,4 +1,3 @@
import ast
import importlib
import os
from functools import total_ordering
@ -106,27 +105,11 @@ class Analysis(object):
last_module_version.analyse_missing_module()
def estimate_workload(self, ctx):
logger.info("Estimate workload...")
logger.info("Estimate workload ...")
for odoo_module in self.modules:
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)")
@ -201,14 +184,14 @@ class Analysis(object):
state = "renamed"
new_module_name = renamed_modules[odoo_module.name]
logger.debug(
f"{previous_version} -> {current_version}:"
f"{previous_version} -> {current_version} :"
f" {odoo_module.name} renamed into {new_module_name}"
)
elif odoo_module.name in merged_modules:
state = "merged"
new_module_name = merged_modules[odoo_module.name]
logger.debug(
f"{previous_version} -> {current_version}:"
f"{previous_version} -> {current_version} :"
f" {odoo_module.name} merged into {new_module_name}"
)
@ -291,27 +274,22 @@ class Analysis(object):
odoo_modules = self.modules
return len(odoo_modules)
def workload(self, module_type, repository):
odoo_modules = self.modules
def workload_hour_text(self, module_type=False):
if module_type:
odoo_modules = [
x
for x in filter(
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
lambda x: x.module_type == module_type, self.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 total
return "%d h" % (int(round(total / 60)))
@total_ordering
@ -349,7 +327,7 @@ class OdooModule(object):
return res
def get_odoo_apps_url(self):
logger.info(f"Searching {self.name} in the Odoo appstore...")
logger.info(f"Searching {self.name} in the Odoo appstore ...")
url = (
f"https://apps.odoo.com/apps/modules/"
f"{self.analyse.initial_version}/{self.name}/"
@ -364,7 +342,7 @@ class OdooModule(object):
return False
def get_odoo_code_search_url(self):
logger.info(f"Searching {self.name} in Odoo-Code-Search...")
logger.info(f"Searching {self.name} in Odoo-Code-Search ...")
url = (
f"https://odoo-code-search.com/ocs/search?"
f"q=name%3A%3D{self.name}+version%3A{self.analyse.initial_version}"
@ -495,7 +473,7 @@ class OdooModuleVersion(object):
"doc",
"description",
]
_manifest_files = ["__openerp__.py", "__manifest__.py"]
_exclude_files = ["__openerp__.py", "__manifest__.py"]
_file_extensions = [".py", ".xml", ".js"]
@ -537,63 +515,6 @@ 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"]
@ -684,7 +605,7 @@ class OdooModuleVersion(object):
if set(Path(relative_path).parts) & set(self._exclude_directories):
continue
for name in files:
if name in self._manifest_files:
if name in self._exclude_files:
continue
filename, file_extension = os.path.splitext(name)
if file_extension in self._file_extensions:

View File

@ -42,7 +42,7 @@ def get_postgres_container(ctx):
# Check if volume exists
try:
client.volumes.get(volume_name)
logger.debug(f"Recovering existing PostgreSQL volume: {volume_name}")
logger.debug(f"Recovering existing postgres volume: {volume_name}")
except docker.errors.NotFound:
logger.info(f"Creating Postgres volume: {volume_name}")
client.volumes.create(volume_name)
@ -53,7 +53,7 @@ def get_postgres_container(ctx):
for key, value in postgres_extra_settings.items():
command += f" -c {key}={value}"
logger.info(f"Launching PostgreSQL Container. (Image {image_name})")
logger.info(f"Launching Postgres Container. (Image {image_name})")
# base environement variables
environments = {
@ -69,7 +69,7 @@ def get_postgres_container(ctx):
postgres_version = float(image_name.split(":")[1])
except ValueError:
raise Exception(
"Unable to extract PostgreSQL version "
"Unable to extract postgres version "
f"from image name {image_name}. "
"Define version in the image name is mandatory."
)
@ -102,7 +102,6 @@ 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.
@ -120,8 +119,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 directory {ctx.obj['env_folder_path']} available"
" in the PostgreSQL container."
f" main folder {ctx.obj['env_folder_path']} available"
" in the postgres container."
)
relative_path = Path(
str(sql_file).replace(str(ctx.obj["env_folder_path"]), ".")
@ -132,7 +131,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 PostgreSQL container"
f"Executing the script '{relative_path}' in postgres container"
f" on database {database}"
)
exec_container(container, command)
@ -163,7 +162,7 @@ def execute_psql_command(
f" {' '.join(psql_args)}"
)
logger.debug(
f"Executing the following command in PostgreSQL container\n{command}"
f"Executing the following command in postgres container\n{command}"
)
docker_result = exec_container(container, command)
return docker_result.output.decode("utf-8")
@ -241,7 +240,7 @@ def chown_to_local_user(ctx, filepath: os.PathLike):
uid=user_uid, filepath=filepath
)
logger.debug(
f"Executing the following command in PostgreSQL container:\n{command}"
f"Executing the following command in postgres container:\n{command}"
)
chown_result = exec_container(container, command)
return chown_result.output.decode("utf8")
@ -277,7 +276,7 @@ def execute_pg_dump(
pg_dump_args=pg_dump_args,
)
logger.debug(
f"Executing the following command in PostgreSQL container:\n{command}"
f"Executing the following command in postgres 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 directory '{folder_path}'")
logger.info(f"Make writable the folder '{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 = ["-p", folder_path]
cmd = ["-m", mode] + cmd
logger.info(f"Creating directory '{folder_path}'...")
cmd = ["--parents", folder_path]
cmd = ["--mode", mode] + cmd
logger.info(f"Creating folder '{folder_path}' ...")
mkdir(cmd)
if git_ignore_content:
@ -74,35 +74,31 @@ def ensure_file_exists_from_template(
if data == output:
return
log_text = f"Updating file '{file_path}' from template..."
log_text = f"Updating file '{file_path}' from template ..."
else:
log_text = f"Creating file '{file_path}' from template..."
log_text = f"Creating file '{file_path}' from template ..."
with open(file_path, "w") as f:
logger.info(log_text)
print(output, file=f)
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)
def git_aggregate(folder_path: Path, config_path: Path, jobs: int):
args = argparse.Namespace(
command="aggregate",
config=str(config_path),
jobs=jobs,
dirmatch=None,
do_push=False,
expand_env=True,
env_file=env_file,
expand_env=False,
env_file=None,
force=True,
)
with working_directory_keeper:
os.chdir(folder_path)
logger.info(
f"Gitaggregate source code for {config_path}."
" This can take a while..."
" This can take a while ..."
)
gitaggregate_cmd.run(args)
@ -177,12 +173,3 @@ 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)

116
poetry.lock generated
View File

@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 2.0.0 and should not be changed by hand.
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
[[package]]
name = "argcomplete"
@ -6,7 +6,6 @@ version = "3.5.1"
description = "Bash tab completion for argparse"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "argcomplete-3.5.1-py3-none-any.whl", hash = "sha256:1a1d148bdaa3e3b93454900163403df41448a248af01b6e849edc5ac08e6c363"},
{file = "argcomplete-3.5.1.tar.gz", hash = "sha256:eb1ee355aa2557bd3d0145de7b06b2a45b0ce461e1e7813f5d066039ab4177b4"},
@ -21,7 +20,6 @@ version = "3.3.5"
description = "An abstract syntax tree for Python with inference support."
optional = false
python-versions = ">=3.9.0"
groups = ["dev"]
files = [
{file = "astroid-3.3.5-py3-none-any.whl", hash = "sha256:a9d1c946ada25098d790e079ba2a1b112157278f3fb7e718ae6a9252f5835dc8"},
{file = "astroid-3.3.5.tar.gz", hash = "sha256:5cfc40ae9f68311075d27ef68a4841bdc5cc7f6cf86671b49f00607d30188e2d"},
@ -36,8 +34,6 @@ version = "1.4.1"
description = "Atomic file writes."
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
groups = ["dev"]
markers = "python_version < \"3.10\" and sys_platform == \"win32\""
files = [
{file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"},
]
@ -48,8 +44,6 @@ version = "24.2.0"
description = "Classes Without Boilerplate"
optional = false
python-versions = ">=3.7"
groups = ["dev"]
markers = "python_version < \"3.10\""
files = [
{file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"},
{file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"},
@ -69,8 +63,6 @@ version = "5.5.0"
description = "Extensible memoizing collections and decorators"
optional = false
python-versions = ">=3.7"
groups = ["dev"]
markers = "python_version >= \"3.10\""
files = [
{file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"},
{file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"},
@ -82,7 +74,6 @@ version = "2024.8.30"
description = "Python package for providing Mozilla's CA Bundle."
optional = false
python-versions = ">=3.6"
groups = ["main", "dev"]
files = [
{file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"},
{file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"},
@ -94,12 +85,10 @@ version = "5.2.0"
description = "Universal encoding detector for Python 3"
optional = false
python-versions = ">=3.7"
groups = ["main", "dev"]
files = [
{file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"},
{file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"},
]
markers = {dev = "python_version >= \"3.10\""}
[[package]]
name = "charset-normalizer"
@ -107,7 +96,6 @@ version = "3.4.0"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
optional = false
python-versions = ">=3.7.0"
groups = ["main", "dev"]
files = [
{file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"},
{file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"},
@ -222,7 +210,6 @@ version = "7.1.2"
description = "Composable command line interface toolkit"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
groups = ["main", "dev"]
files = [
{file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"},
{file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"},
@ -234,7 +221,6 @@ version = "0.4.0.post1"
description = "Log level parameter type for Click"
optional = false
python-versions = "~=3.6"
groups = ["main"]
files = [
{file = "click-loglevel-0.4.0.post1.tar.gz", hash = "sha256:470bf1e208fe650cedacb23061e4e18d36df601ca9d8b79e6d8e8cdf1792ece1"},
{file = "click_loglevel-0.4.0.post1-py3-none-any.whl", hash = "sha256:f3449b5d28d6cba5bfbeed371ad59950aba035730d5cc28a32b4e7632e17ed6c"},
@ -249,12 +235,10 @@ version = "0.4.6"
description = "Cross-platform colored terminal text."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
groups = ["main", "dev"]
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
markers = {dev = "sys_platform == \"win32\" or platform_system == \"Windows\" or python_version >= \"3.10\""}
[[package]]
name = "coverage"
@ -262,7 +246,6 @@ version = "7.6.4"
description = "Code coverage measurement for Python"
optional = false
python-versions = ">=3.9"
groups = ["dev"]
files = [
{file = "coverage-7.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07"},
{file = "coverage-7.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0"},
@ -340,7 +323,6 @@ version = "0.3.9"
description = "serialize all of Python"
optional = false
python-versions = ">=3.8"
groups = ["dev"]
files = [
{file = "dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a"},
{file = "dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c"},
@ -356,7 +338,6 @@ version = "0.3.9"
description = "Distribution utilities"
optional = false
python-versions = "*"
groups = ["dev"]
files = [
{file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"},
{file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"},
@ -368,7 +349,6 @@ version = "7.1.0"
description = "A Python library for the Docker Engine API."
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0"},
{file = "docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c"},
@ -391,7 +371,6 @@ version = "0.6.3"
description = "A parser for Python dependency files"
optional = false
python-versions = ">=3.6"
groups = ["dev"]
files = [
{file = "dparse-0.6.3-py3-none-any.whl", hash = "sha256:0d8fe18714056ca632d98b24fbfc4e9791d4e47065285ab486182288813a5318"},
{file = "dparse-0.6.3.tar.gz", hash = "sha256:27bb8b4bcaefec3997697ba3f6e06b2447200ba273c0b085c3d012a04571b528"},
@ -411,8 +390,6 @@ version = "1.2.2"
description = "Backport of PEP 654 (exception groups)"
optional = false
python-versions = ">=3.7"
groups = ["dev"]
markers = "python_version >= \"3.10\" and python_version < \"3.11\""
files = [
{file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
{file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
@ -427,7 +404,6 @@ version = "3.16.1"
description = "A platform independent file lock."
optional = false
python-versions = ">=3.8"
groups = ["dev"]
files = [
{file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"},
{file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"},
@ -444,7 +420,6 @@ version = "2.1.0"
description = "A library to aggregate git branches from different remotes into a consolidated one"
optional = false
python-versions = ">=3.6"
groups = ["main"]
files = [
{file = "git-aggregator-2.1.0.tar.gz", hash = "sha256:efdc4d3f360fd63ef5b14e7064ce5edb14ea404c6a4047715cfc5b9384ff49cc"},
{file = "git_aggregator-2.1.0-py3-none-any.whl", hash = "sha256:59986c0ff7a1641849504dc4d86491872d9f65b46a076aac4bf21cd550ff61df"},
@ -462,7 +437,6 @@ version = "4.0.11"
description = "Git Object Database"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4"},
{file = "gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"},
@ -477,7 +451,6 @@ version = "3.1.43"
description = "GitPython is a Python library used to interact with Git repositories"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "GitPython-3.1.43-py3-none-any.whl", hash = "sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff"},
{file = "GitPython-3.1.43.tar.gz", hash = "sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c"},
@ -496,7 +469,6 @@ version = "3.10"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.6"
groups = ["main", "dev"]
files = [
{file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"},
{file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"},
@ -511,8 +483,6 @@ version = "8.5.0"
description = "Read metadata from Python packages"
optional = false
python-versions = ">=3.8"
groups = ["dev"]
markers = "python_version < \"3.10\""
files = [
{file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"},
{file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"},
@ -536,7 +506,6 @@ version = "5.13.0"
description = "Read resources from Python packages"
optional = false
python-versions = ">=3.8"
groups = ["main", "dev"]
files = [
{file = "importlib_resources-5.13.0-py3-none-any.whl", hash = "sha256:9f7bd0c97b79972a6cce36a366356d16d5e13b09679c11a58f1014bfdf8e64b2"},
{file = "importlib_resources-5.13.0.tar.gz", hash = "sha256:82d5c6cca930697dbbd86c93333bb2c2e72861d4789a11c2662b933e5ad2b528"},
@ -555,7 +524,6 @@ version = "2.0.0"
description = "brain-dead simple config-ini parsing"
optional = false
python-versions = ">=3.7"
groups = ["dev"]
files = [
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
@ -567,7 +535,6 @@ version = "5.13.2"
description = "A Python utility / library to sort Python imports."
optional = false
python-versions = ">=3.8.0"
groups = ["dev"]
files = [
{file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"},
{file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"},
@ -582,7 +549,6 @@ version = "3.1.4"
description = "A very fast and expressive template engine."
optional = false
python-versions = ">=3.7"
groups = ["main", "dev"]
files = [
{file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"},
{file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"},
@ -600,7 +566,6 @@ version = "0.6.0"
description = "Configuration manager"
optional = false
python-versions = "*"
groups = ["main"]
files = [
{file = "kaptan-0.6.0-py3-none-any.whl", hash = "sha256:05b6a3d9eb4c4e53173519491cf32847a56d923226145938f1ffce547e4eac27"},
{file = "kaptan-0.6.0.tar.gz", hash = "sha256:101330a44fdede888586f3010bd145c0ec48a4806bc56429fa5487a6774021f8"},
@ -615,7 +580,6 @@ version = "0.6.0"
description = "Python logging made (stupidly) simple"
optional = false
python-versions = ">=3.5"
groups = ["main"]
files = [
{file = "loguru-0.6.0-py3-none-any.whl", hash = "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3"},
{file = "loguru-0.6.0.tar.gz", hash = "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c"},
@ -634,7 +598,6 @@ version = "3.0.0"
description = "Python port of markdown-it. Markdown parsing, done right!"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
{file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
@ -659,7 +622,6 @@ version = "3.0.2"
description = "Safely add untrusted strings to HTML/XML markup."
optional = false
python-versions = ">=3.9"
groups = ["main", "dev"]
files = [
{file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"},
{file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"},
@ -730,7 +692,6 @@ version = "0.7.0"
description = "McCabe checker, plugin for flake8"
optional = false
python-versions = ">=3.6"
groups = ["dev"]
files = [
{file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
{file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
@ -742,7 +703,6 @@ version = "0.1.2"
description = "Markdown URL utilities"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
@ -754,7 +714,6 @@ version = "0.10.1"
description = "OdooRPC is a Python package providing an easy way to pilot your Odoo servers through RPC."
optional = false
python-versions = "*"
groups = ["main"]
files = [
{file = "OdooRPC-0.10.1-py2.py3-none-any.whl", hash = "sha256:a0900bdd5c989c414b1ef40dafccd9363f179312d9166d9486cf70c7c2f0dd44"},
{file = "OdooRPC-0.10.1.tar.gz", hash = "sha256:d0bc524c5b960781165575bad9c13d032d6f968c3c09276271045ddbbb483aa5"},
@ -766,7 +725,6 @@ version = "24.1"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.8"
groups = ["dev"]
files = [
{file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
@ -778,7 +736,6 @@ version = "4.3.6"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
optional = false
python-versions = ">=3.8"
groups = ["dev"]
files = [
{file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"},
{file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"},
@ -795,8 +752,6 @@ version = "0.13.1"
description = "plugin and hook calling mechanisms for python"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
groups = ["dev"]
markers = "python_version < \"3.10\""
files = [
{file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
{file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
@ -811,8 +766,6 @@ version = "1.5.0"
description = "plugin and hook calling mechanisms for python"
optional = false
python-versions = ">=3.8"
groups = ["dev"]
markers = "python_version >= \"3.10\""
files = [
{file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
{file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
@ -828,7 +781,6 @@ version = "1.9.0"
description = "Plumbum: shell combinators library"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "plumbum-1.9.0-py3-none-any.whl", hash = "sha256:9fd0d3b0e8d86e4b581af36edf3f3bbe9d1ae15b45b8caab28de1bcb27aaa7f5"},
{file = "plumbum-1.9.0.tar.gz", hash = "sha256:e640062b72642c3873bd5bdc3effed75ba4d3c70ef6b6a7b907357a84d909219"},
@ -849,8 +801,6 @@ version = "1.11.0"
description = "library with cross-python path, ini-parsing, io, code, log facilities"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
groups = ["dev"]
markers = "python_version < \"3.10\""
files = [
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
@ -862,7 +812,6 @@ version = "2.18.0"
description = "Pygments is a syntax highlighting package written in Python."
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"},
{file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"},
@ -877,7 +826,6 @@ version = "1.6.1"
description = "count source lines of code (SLOC) using pygments"
optional = false
python-versions = ">=3.8,<4"
groups = ["main"]
files = [
{file = "pygount-1.6.1-py3-none-any.whl", hash = "sha256:85b1d06d51398150fe6de3ec39feca867e95dc9c7a1a45f4dee731ab43177bcf"},
{file = "pygount-1.6.1.tar.gz", hash = "sha256:fac00c6bd61ab6d7633fe8724ae73943cde169de4f2a014244a488037a14d385"},
@ -895,7 +843,6 @@ version = "3.3.1"
description = "python code static checker"
optional = false
python-versions = ">=3.9.0"
groups = ["dev"]
files = [
{file = "pylint-3.3.1-py3-none-any.whl", hash = "sha256:2f846a466dd023513240bc140ad2dd73bfc080a5d85a710afdb728c420a5a2b9"},
{file = "pylint-3.3.1.tar.gz", hash = "sha256:9f3dcc87b1203e612b78d91a896407787e708b3f189b5fa0b307712d49ff0c6e"},
@ -906,8 +853,8 @@ astroid = ">=3.3.4,<=3.4.0-dev0"
colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
dill = [
{version = ">=0.2", markers = "python_version < \"3.11\""},
{version = ">=0.3.6", markers = "python_version >= \"3.11\""},
{version = ">=0.3.7", markers = "python_version >= \"3.12\""},
{version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""},
]
isort = ">=4.2.5,<5.13.0 || >5.13.0,<6"
mccabe = ">=0.6,<0.8"
@ -926,8 +873,6 @@ version = "1.8.0"
description = "API to interact with the python pyproject.toml based projects"
optional = false
python-versions = ">=3.8"
groups = ["dev"]
markers = "python_version >= \"3.10\""
files = [
{file = "pyproject_api-1.8.0-py3-none-any.whl", hash = "sha256:3d7d347a047afe796fd5d1885b1e391ba29be7169bd2f102fcd378f04273d228"},
{file = "pyproject_api-1.8.0.tar.gz", hash = "sha256:77b8049f2feb5d33eefcc21b57f1e279636277a8ac8ad6b5871037b243778496"},
@ -947,8 +892,6 @@ version = "6.1.2"
description = "pytest: simple powerful testing with Python"
optional = false
python-versions = ">=3.5"
groups = ["dev"]
markers = "python_version < \"3.10\""
files = [
{file = "pytest-6.1.2-py3-none-any.whl", hash = "sha256:4288fed0d9153d9646bfcdf0c0428197dba1ecb27a33bb6e031d002fa88653fe"},
{file = "pytest-6.1.2.tar.gz", hash = "sha256:c0a7e94a8cdbc5422a51ccdad8e6f1024795939cc89159a0ae7f0b316ad3823e"},
@ -974,8 +917,6 @@ version = "8.3.3"
description = "pytest: simple powerful testing with Python"
optional = false
python-versions = ">=3.8"
groups = ["dev"]
markers = "python_version >= \"3.10\""
files = [
{file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"},
{file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"},
@ -994,18 +935,17 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments
[[package]]
name = "pytest-cov"
version = "6.0.0"
version = "5.0.0"
description = "Pytest plugin for measuring coverage."
optional = false
python-versions = ">=3.9"
groups = ["dev"]
python-versions = ">=3.8"
files = [
{file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"},
{file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"},
{file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"},
{file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"},
]
[package.dependencies]
coverage = {version = ">=7.5", extras = ["toml"]}
coverage = {version = ">=5.2.1", extras = ["toml"]}
pytest = ">=4.6"
[package.extras]
@ -1017,7 +957,6 @@ version = "3.6.1"
description = "Thin-wrapper around the mock package for easier use with pytest"
optional = false
python-versions = ">=3.6"
groups = ["dev"]
files = [
{file = "pytest-mock-3.6.1.tar.gz", hash = "sha256:40217a058c52a63f1042f0784f62009e976ba824c418cced42e88d5f40ab0e62"},
{file = "pytest_mock-3.6.1-py3-none-any.whl", hash = "sha256:30c2f2cc9759e76eee674b81ea28c9f0b94f8f0445a1b87762cadf774f0df7e3"},
@ -1035,8 +974,6 @@ version = "308"
description = "Python for Window Extensions"
optional = false
python-versions = "*"
groups = ["main"]
markers = "platform_system == \"Windows\" and platform_python_implementation != \"PyPy\" or sys_platform == \"win32\""
files = [
{file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"},
{file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"},
@ -1064,7 +1001,6 @@ version = "6.0.2"
description = "YAML parser and emitter for Python"
optional = false
python-versions = ">=3.8"
groups = ["main"]
files = [
{file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"},
{file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"},
@ -1127,7 +1063,6 @@ version = "2.32.3"
description = "Python HTTP for Humans."
optional = false
python-versions = ">=3.8"
groups = ["main", "dev"]
files = [
{file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
{file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
@ -1145,14 +1080,13 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
[[package]]
name = "rich"
version = "13.9.4"
version = "13.9.3"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
optional = false
python-versions = ">=3.8.0"
groups = ["main"]
files = [
{file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"},
{file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"},
{file = "rich-13.9.3-py3-none-any.whl", hash = "sha256:9836f5096eb2172c9e77df411c1b009bace4193d6a481d534fea75ebba758283"},
{file = "rich-13.9.3.tar.gz", hash = "sha256:bc1e01b899537598cf02579d2b9f4a415104d3fc439313a7a2c165d76557a08e"},
]
[package.dependencies]
@ -1169,7 +1103,6 @@ version = "1.10.3"
description = "Checks installed dependencies for known vulnerabilities."
optional = false
python-versions = ">=3.5"
groups = ["dev"]
files = [
{file = "safety-1.10.3-py2.py3-none-any.whl", hash = "sha256:5f802ad5df5614f9622d8d71fedec2757099705c2356f862847c58c6dfe13e84"},
{file = "safety-1.10.3.tar.gz", hash = "sha256:30e394d02a20ac49b7f65292d19d38fa927a8f9582cdfd3ad1adbbc66c641ad5"},
@ -1188,7 +1121,6 @@ version = "75.3.0"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false
python-versions = ">=3.8"
groups = ["dev"]
files = [
{file = "setuptools-75.3.0-py3-none-any.whl", hash = "sha256:f2504966861356aa38616760c0f66568e535562374995367b4e69c7143cf6bcd"},
{file = "setuptools-75.3.0.tar.gz", hash = "sha256:fba5dd4d766e97be1b1681d98712680ae8f2f26d7881245f2ce9e40714f1a686"},
@ -1209,7 +1141,6 @@ version = "0.3.0"
description = "Access to the project version in Python code for PEP 621-style projects"
optional = false
python-versions = ">=3.6,<4.0"
groups = ["main"]
files = [
{file = "single-source-0.3.0.tar.gz", hash = "sha256:b12705af958ca99d56ea9ce40bd9cc749378f4fe7ad03b1f9067e29daceef27d"},
{file = "single_source-0.3.0-py3-none-any.whl", hash = "sha256:7bc87168ced50f638b6ab0cda4cc1ce9e80ee0e1220014397050d336d021a597"},
@ -1221,8 +1152,6 @@ version = "1.16.0"
description = "Python 2 and 3 compatibility utilities"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
groups = ["dev"]
markers = "python_version < \"3.10\""
files = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
@ -1234,7 +1163,6 @@ version = "5.0.1"
description = "A pure Python implementation of a sliding window memory map manager"
optional = false
python-versions = ">=3.7"
groups = ["main"]
files = [
{file = "smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"},
{file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"},
@ -1246,8 +1174,6 @@ version = "0.10.2"
description = "Python Library for Tom's Obvious, Minimal Language"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
groups = ["dev"]
markers = "python_version < \"3.10\""
files = [
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
@ -1259,8 +1185,6 @@ version = "2.0.2"
description = "A lil' TOML parser"
optional = false
python-versions = ">=3.8"
groups = ["dev"]
markers = "python_version < \"3.11\""
files = [
{file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"},
{file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"},
@ -1272,7 +1196,6 @@ version = "0.13.2"
description = "Style preserving TOML library"
optional = false
python-versions = ">=3.8"
groups = ["dev"]
files = [
{file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"},
{file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"},
@ -1284,7 +1207,6 @@ version = "24.8.0"
description = "Building newsfiles for your project."
optional = false
python-versions = ">=3.8"
groups = ["dev"]
files = [
{file = "towncrier-24.8.0-py3-none-any.whl", hash = "sha256:9343209592b839209cdf28c339ba45792fbfe9775b5f9c177462fd693e127d8d"},
{file = "towncrier-24.8.0.tar.gz", hash = "sha256:013423ee7eed102b2f393c287d22d95f66f1a3ea10a4baa82d298001a7f18af3"},
@ -1306,8 +1228,6 @@ version = "3.28.0"
description = "tox is a generic virtualenv management and test command line tool"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
groups = ["dev"]
markers = "python_version < \"3.10\""
files = [
{file = "tox-3.28.0-py2.py3-none-any.whl", hash = "sha256:57b5ab7e8bb3074edc3c0c0b4b192a4f3799d3723b2c5b76f1fa9f2d40316eea"},
{file = "tox-3.28.0.tar.gz", hash = "sha256:d0d28f3fe6d6d7195c27f8b054c3e99d5451952b54abdae673b71609a581f640"},
@ -1333,8 +1253,6 @@ version = "4.23.2"
description = "tox is a generic virtualenv management and test command line tool"
optional = false
python-versions = ">=3.8"
groups = ["dev"]
markers = "python_version >= \"3.10\""
files = [
{file = "tox-4.23.2-py3-none-any.whl", hash = "sha256:452bc32bb031f2282881a2118923176445bac783ab97c874b8770ab4c3b76c38"},
{file = "tox-4.23.2.tar.gz", hash = "sha256:86075e00e555df6e82e74cfc333917f91ecb47ffbc868dcafbd2672e332f4a2c"},
@ -1362,8 +1280,6 @@ version = "4.12.2"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
groups = ["main", "dev"]
markers = "python_version < \"3.11\""
files = [
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
@ -1375,7 +1291,6 @@ version = "2.2.3"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
python-versions = ">=3.8"
groups = ["main", "dev"]
files = [
{file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"},
{file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"},
@ -1393,7 +1308,6 @@ version = "20.27.1"
description = "Virtual Python Environment builder"
optional = false
python-versions = ">=3.8"
groups = ["dev"]
files = [
{file = "virtualenv-20.27.1-py3-none-any.whl", hash = "sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4"},
{file = "virtualenv-20.27.1.tar.gz", hash = "sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba"},
@ -1414,8 +1328,6 @@ version = "1.1.0"
description = "A small Python utility to set file creation time on Windows"
optional = false
python-versions = ">=3.5"
groups = ["main"]
markers = "sys_platform == \"win32\""
files = [
{file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"},
{file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"},
@ -1430,8 +1342,6 @@ version = "3.20.2"
description = "Backport of pathlib-compatible object wrapper for zip files"
optional = false
python-versions = ">=3.8"
groups = ["main", "dev"]
markers = "python_version < \"3.10\""
files = [
{file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"},
{file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"},
@ -1446,6 +1356,6 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools",
type = ["pytest-mypy"]
[metadata]
lock-version = "2.1"
python-versions = ">=3.9,<4.0"
content-hash = "bd83f44e877cb1003740b4a7285e4be58335014bdd7988e659e7a41034d4787b"
lock-version = "2.0"
python-versions = ">=3.9,<4.0.0"
content-hash = "fe1d6b134fdac318f9b27745a752250a8784832e97d43ca2f9f31066b0b3bbc5"

View File

@ -1,15 +1,15 @@
[project]
[tool.poetry]
name = "odoo-openupgrade-wizard"
version = "1.3.1.1"
version = "1.0.3"
description = "CLI tool to manage Odoo Major Upgrades"
authors = [
{name = "Sylvain LE GAL", email = "sylvain.legal@grap.coop"},
{name = "Rémy TAYMANS", email = "remy@coopiteasy.be"},
{name = "Simon MAILLARD", email = "simon@ogesta.fr"},
"Sylvain LE GAL <sylvain.legal@grap.coop>",
"Rémy TAYMANS <remy@coopiteasy.be>",
"Simon MAILLARD <simon@ogesta.fr>",
]
maintainers = [
{name = "Sylvain LE GAL", email = "sylvain.legal@grap.coop"},
{name = "Rémy TAYMANS", email = "remy@coopiteasy.be"},
"Sylvain LE GAL <sylvain.legal@grap.coop>",
"Rémy TAYMANS <remy@coopiteasy.be>",
]
readme = "README.md"
repository = "https://gitlab.com/odoo-openupgrade-wizard/odoo-openupgrade-wizard"
@ -23,34 +23,32 @@ 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",
"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"
[project.scripts]
[tool.poetry.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 = [

1
python3-13.misc Normal file
View File

@ -0,0 +1 @@
Add support of python 3.13.

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(["-p", test_folder_path])
mkdir([test_folder_path, "--parents"])
os.chdir(test_folder_path)

View File

@ -1,23 +0,0 @@
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,38 +45,6 @@ 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

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

View File

@ -1,4 +0,0 @@
# 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.